diff options
426 files changed, 13596 insertions, 14490 deletions
@@ -1,19 +1,6 @@ -# Bug component: 27441 +set noparent -# Project owners -girardier@google.com #{LAST_RESORT_SUGGESTION} -muhammadfalam@google.com #{LAST_RESORT_SUGGESTION} -siyuanh@google.com #{LAST_RESORT_SUGGESTION} -okamil@google.com #{LAST_RESORT_SUGGESTION} -wescande@google.com #{LAST_RESORT_SUGGESTION} - -# Per-file ownership - -# Build files / test_config / presubmit / preupload / linter file -per-file *.cfg,.cfg,TEST_MAPPING,*.bp,*.xml,.clang-tidy,pyrightconfig.json=file:/OWNERS_build - -# ChromeOS team owns Linux build files -# - build.py is used for Linux build -# - *.gn is for GN build rules -# - Cargo.toml is for Rust build rules -per-file build.py,*.gn,Cargo.toml=file:/OWNERS_chromeos +girardier@google.com +muhammadfalam@google.com +okamil@google.com +siyuanh@google.com diff --git a/OWNERS_automotive b/OWNERS_automotive deleted file mode 100644 index 20c7ac685b..0000000000 --- a/OWNERS_automotive +++ /dev/null @@ -1,3 +0,0 @@ -# Project owners -cmanton@google.com -salsavage@google.com diff --git a/OWNERS_build b/OWNERS_build deleted file mode 100644 index 5b3f4bad26..0000000000 --- a/OWNERS_build +++ /dev/null @@ -1 +0,0 @@ -wescande@google.com diff --git a/OWNERS_channel_sounding b/OWNERS_channel_sounding deleted file mode 100644 index 10a8fa893a..0000000000 --- a/OWNERS_channel_sounding +++ /dev/null @@ -1,9 +0,0 @@ -# Pixel DRI -aliceypkuo@google.com -chienyuanhuang@google.com - -# Bluetooth Ranging DRI -steveliu@google.com - -# Bluetooth Stack Reviewer -henrichataing@google.com diff --git a/OWNERS_chromeos b/OWNERS_chromeos deleted file mode 100644 index 075a04e5e3..0000000000 --- a/OWNERS_chromeos +++ /dev/null @@ -1,22 +0,0 @@ -# Project owners -abhishekpandit@google.com - -# Audio -enshuo@google.com -hychao@google.com -jrwu@google.com -whalechang@google.com - -# General review -michaelfsun@google.com -laikatherine@google.com -yinghsu@google.com -apusaka@google.com -deanliao@google.com -chharry@google.com -melhuishj@google.com -johnlai@google.com -mmandlik@google.com -sarveshkalwit@google.com -howardchung@google.com -jiangzp@google.com diff --git a/OWNERS_content b/OWNERS_content deleted file mode 100644 index 883d5dc782..0000000000 --- a/OWNERS_content +++ /dev/null @@ -1,2 +0,0 @@ -klhyun@google.com -hdmoon@google.com diff --git a/OWNERS_cs b/OWNERS_cs deleted file mode 100644 index 1cebb11002..0000000000 --- a/OWNERS_cs +++ /dev/null @@ -1,2 +0,0 @@ -steveliu@google.com -zning@google.com diff --git a/OWNERS_hearingaid b/OWNERS_hearingaid deleted file mode 100644 index d1c75de900..0000000000 --- a/OWNERS_hearingaid +++ /dev/null @@ -1 +0,0 @@ -henrichataing@google.com diff --git a/OWNERS_leaudio b/OWNERS_leaudio deleted file mode 100644 index 30db38d799..0000000000 --- a/OWNERS_leaudio +++ /dev/null @@ -1,3 +0,0 @@ -siyuanh@google.com -jpawlowski@google.com -rongxuan@google.com diff --git a/TEST_MAPPING b/TEST_MAPPING index b1cc9a7594..c807f7d8ec 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -133,9 +133,6 @@ "name": "net_test_bta_security" }, { - "name": "net_test_btcore" - }, - { "name": "net_test_btif" }, { @@ -365,9 +362,6 @@ "name": "net_test_bta_security" }, { - "name": "net_test_btcore" - }, - { "name": "net_test_btif" }, { diff --git a/android/BluetoothLegacyMigration/OWNERS b/android/BluetoothLegacyMigration/OWNERS deleted file mode 100644 index 66467c7b3e..0000000000 --- a/android/BluetoothLegacyMigration/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -# Reviewers for /android/BluetoothLegacyMigration - -eruffieux@google.com -siyuanh@google.com -wescande@google.com diff --git a/android/ChannelSoundingTestApp/OWNERS b/android/ChannelSoundingTestApp/OWNERS deleted file mode 100644 index 29d6f601cc..0000000000 --- a/android/ChannelSoundingTestApp/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_cs diff --git a/android/apishim/OWNERS b/android/apishim/OWNERS deleted file mode 100644 index 586d2866f1..0000000000 --- a/android/apishim/OWNERS +++ /dev/null @@ -1,6 +0,0 @@ -# Reviewers for /android/apishim - -eruffieux@google.com -jpawlowski@google.com -siyuanh@google.com -wescande@google.com diff --git a/android/app/OWNERS b/android/app/OWNERS deleted file mode 100644 index 7b7e2e6679..0000000000 --- a/android/app/OWNERS +++ /dev/null @@ -1,15 +0,0 @@ -# Reviewers for /android/app - -bhaktha@google.com -eruffieux@google.com -hallstrom@google.com -henrichataing@google.com -jpawlowski@google.com -okamil@google.com -poahlo@google.com -siyuanh@google.com -wescande@google.com -rwt@google.com - -# Reviewers for Channel Sounding related files -per-file /src/com/android/bluetooth/gatt/DistanceMeasurement*.java=file:/OWNERS_channel_sounding diff --git a/android/app/aidl/android/bluetooth/BluetoothClass.aidl b/android/app/aidl/android/bluetooth/BluetoothClass.aidl index 8699b1eee3..124ee53760 100644 --- a/android/app/aidl/android/bluetooth/BluetoothClass.aidl +++ b/android/app/aidl/android/bluetooth/BluetoothClass.aidl @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/aidl/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl b/android/app/aidl/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl index 14f91140af..74f51a8037 100644 --- a/android/app/aidl/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl +++ b/android/app/aidl/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl @@ -5,7 +5,7 @@ ** 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 +** 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, diff --git a/android/app/aidl/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl b/android/app/aidl/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl index 87dd10ee15..a55a794c6e 100644 --- a/android/app/aidl/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl +++ b/android/app/aidl/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl @@ -5,7 +5,7 @@ ** 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 +** 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, diff --git a/android/app/aidl/android/bluetooth/IBluetooth.aidl b/android/app/aidl/android/bluetooth/IBluetooth.aidl index bc46353f7c..d8a5421d6f 100644 --- a/android/app/aidl/android/bluetooth/IBluetooth.aidl +++ b/android/app/aidl/android/bluetooth/IBluetooth.aidl @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/aidl/android/bluetooth/IBluetoothCallback.aidl b/android/app/aidl/android/bluetooth/IBluetoothCallback.aidl index 9b2888eadb..6101044e29 100644 --- a/android/app/aidl/android/bluetooth/IBluetoothCallback.aidl +++ b/android/app/aidl/android/bluetooth/IBluetoothCallback.aidl @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/aidl/android/bluetooth/IBluetoothSocketManager.aidl b/android/app/aidl/android/bluetooth/IBluetoothSocketManager.aidl index ce2397ff33..bd54982d13 100644 --- a/android/app/aidl/android/bluetooth/IBluetoothSocketManager.aidl +++ b/android/app/aidl/android/bluetooth/IBluetoothSocketManager.aidl @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/aidl/android/bluetooth/IncomingRfcommSocketInfo.aidl b/android/app/aidl/android/bluetooth/IncomingRfcommSocketInfo.aidl index 38ffe6f699..c3d542c774 100644 --- a/android/app/aidl/android/bluetooth/IncomingRfcommSocketInfo.aidl +++ b/android/app/aidl/android/bluetooth/IncomingRfcommSocketInfo.aidl @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/jni/OWNERS b/android/app/jni/OWNERS deleted file mode 100644 index 826f56b4e0..0000000000 --- a/android/app/jni/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -per-file com_android_bluetooth_hearing_aid.cpp=file:/OWNERS_hearingaid -per-file com_android_bluetooth_csip_set_coordinator.cpp=file:/OWNERS_leaudio -per-file com_android_bluetooth_le_audio.cpp=file:/OWNERS_leaudio -per-file com_android_bluetooth_vc.cpp=file:/OWNERS_leaudio diff --git a/android/app/jni/com_android_bluetooth_gatt.cpp b/android/app/jni/com_android_bluetooth_gatt.cpp index acd609f8bd..be0922c8fc 100644 --- a/android/app/jni/com_android_bluetooth_gatt.cpp +++ b/android/app/jni/com_android_bluetooth_gatt.cpp @@ -2353,7 +2353,11 @@ static AdvertiseParameters parseParams(JNIEnv* env, jobject i) { p.secondary_advertising_phy = secondaryPhy; p.scan_request_notification_enable = false; p.own_address_type = ownAddressType; - p.peer_address = str2addr(env, peerAddress); + if (peerAddress == nullptr) { + p.peer_address = RawAddress::kEmpty; + } else { + p.peer_address = str2addr(env, peerAddress); + } p.peer_address_type = peerAddressType; p.discoverable = isDiscoverable; return p; diff --git a/android/app/jni/com_android_bluetooth_hfp.cpp b/android/app/jni/com_android_bluetooth_hfp.cpp index 18a0bf1950..f321497e16 100644 --- a/android/app/jni/com_android_bluetooth_hfp.cpp +++ b/android/app/jni/com_android_bluetooth_hfp.cpp @@ -651,7 +651,8 @@ static jboolean isVoiceRecognitionSupportedNative(JNIEnv* env, jobject /* object return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } -static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject /* object */, jbyteArray address) { +static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject /* object */, jbyteArray address, + jboolean sendResult) { std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothHfpInterface) { log::warn("sBluetoothHfpInterface is null"); @@ -663,7 +664,7 @@ static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject /* object */, j jniThrowIOException(env, EINVAL); return JNI_FALSE; } - bt_status_t status = sBluetoothHfpInterface->StartVoiceRecognition((RawAddress*)addr); + bt_status_t status = sBluetoothHfpInterface->StartVoiceRecognition((RawAddress*)addr, sendResult); if (status != BT_STATUS_SUCCESS) { log::error("Failed to start voice recognition, status: {}", bt_status_text(status)); } @@ -986,7 +987,7 @@ int register_com_android_bluetooth_hfp(JNIEnv* env) { {"disconnectAudioNative", "([B)Z", (void*)disconnectAudioNative}, {"isNoiseReductionSupportedNative", "([B)Z", (void*)isNoiseReductionSupportedNative}, {"isVoiceRecognitionSupportedNative", "([B)Z", (void*)isVoiceRecognitionSupportedNative}, - {"startVoiceRecognitionNative", "([B)Z", (void*)startVoiceRecognitionNative}, + {"startVoiceRecognitionNative", "([BZ)Z", (void*)startVoiceRecognitionNative}, {"stopVoiceRecognitionNative", "([B)Z", (void*)stopVoiceRecognitionNative}, {"setVolumeNative", "(II[B)Z", (void*)setVolumeNative}, {"notifyDeviceStatusNative", "(IIII[B)Z", (void*)notifyDeviceStatusNative}, diff --git a/android/app/res/values-as/strings.xml b/android/app/res/values-as/strings.xml index 2776941946..c53ee123e2 100644 --- a/android/app/res/values-as/strings.xml +++ b/android/app/res/values-as/strings.xml @@ -35,7 +35,7 @@ <string name="incoming_file_confirm_content" msgid="6573502088511901157">"অন্তৰ্গামী ফাইল গ্ৰহণ কৰিবনে?"</string> <string name="incoming_file_confirm_cancel" msgid="9205906062663982692">"প্ৰত্যাখ্যান কৰক"</string> <string name="incoming_file_confirm_ok" msgid="5046926299036238623">"গ্ৰহণ কৰক"</string> - <string name="incoming_file_confirm_timeout_ok" msgid="8612187577686515660">"ঠিক"</string> + <string name="incoming_file_confirm_timeout_ok" msgid="8612187577686515660">"ঠিক আছে"</string> <string name="incoming_file_confirm_timeout_content" msgid="3221412098281076974">"\"<xliff:g id="SENDER">%1$s</xliff:g>\"ৰ পৰা লাভ কৰা ফাইলটো গ্ৰহণ কৰোঁতে সময় ওকলিছে"</string> <string name="incoming_file_confirm_Notification_title" msgid="5381395500920804895">"অন্তৰ্গামী ফাইল"</string> <string name="incoming_file_confirm_Notification_content" msgid="2669135531488877921">"<xliff:g id="SENDER">%1$s</xliff:g> এটা ফাইল পঠিয়াবলৈ সাজু: <xliff:g id="FILE">%2$s</xliff:g>"</string> @@ -58,18 +58,18 @@ <string name="download_fail_line1" msgid="3149552664349685007">"ফাইল লাভ কৰা নহ\'ল"</string> <string name="download_fail_line2" msgid="4289018531070750414">"ফাইল: <xliff:g id="FILE">%1$s</xliff:g>"</string> <string name="download_fail_line3" msgid="2214989413171231684">"কাৰণ: <xliff:g id="REASON">%1$s</xliff:g>"</string> - <string name="download_fail_ok" msgid="3272322648250767032">"ঠিক"</string> + <string name="download_fail_ok" msgid="3272322648250767032">"ঠিক আছে"</string> <string name="download_succ_line5" msgid="1720346308221503270">"ফাইল লাভ কৰা হ’ল"</string> <string name="download_succ_ok" msgid="7488662808922799824">"খোলক"</string> <string name="upload_line1" msgid="1912803923255989287">"প্ৰতি: \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string> <string name="upload_line3" msgid="5964902647036741603">"ফাইলৰ প্ৰকাৰ: <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string> <string name="upload_line5" msgid="3477751464103201364">"ফাইল প্ৰেৰণ কৰি থকা হৈছে…"</string> <string name="upload_succ_line5" msgid="165979135931118211">"ফাইল প্ৰেৰণ কৰা হ’ল"</string> - <string name="upload_succ_ok" msgid="6797291708604959167">"ঠিক"</string> + <string name="upload_succ_ok" msgid="6797291708604959167">"ঠিক আছে"</string> <string name="upload_fail_line1" msgid="7044307783071776426">"\"<xliff:g id="RECIPIENT">%1$s</xliff:g>\"লৈ ফাইলটো পঠিয়াব পৰা নগ\'ল।"</string> <string name="upload_fail_line1_2" msgid="6102642590057711459">"ফাইল: <xliff:g id="FILE">%1$s</xliff:g>"</string> <string name="upload_fail_cancel" msgid="1632528037932779727">"বন্ধ কৰক"</string> - <string name="bt_error_btn_ok" msgid="2802751202009957372">"ঠিক"</string> + <string name="bt_error_btn_ok" msgid="2802751202009957372">"ঠিক আছে"</string> <string name="unknown_file" msgid="3719981572107052685">"অজ্ঞাত ফাইল"</string> <string name="unknown_file_desc" msgid="9185609398960437760">"এইধৰণৰ ফাইল পৰিচালনা কৰিবলৈ কোনো এপ্ নাই। \n"</string> <string name="not_exist_file" msgid="5097565588949092486">"কোনো ফাইল নাই"</string> diff --git a/android/app/src/com/android/bluetooth/BluetoothMethodProxy.java b/android/app/src/com/android/bluetooth/BluetoothMethodProxy.java index d4fc9d54e8..a4c265adf7 100644 --- a/android/app/src/com/android/bluetooth/BluetoothMethodProxy.java +++ b/android/app/src/com/android/bluetooth/BluetoothMethodProxy.java @@ -306,4 +306,9 @@ public class BluetoothMethodProxy { ComponentCaller caller, Uri uri, int modeFlags) { return caller.checkContentUriPermission(uri, modeFlags); } + + /** Proxies {@link Context#grantUriPermission(String, Uri, int)}. } */ + public void grantUriPermission(Context context, String packageName, Uri uri, int modeFlags) { + context.grantUriPermission(packageName, uri, modeFlags); + } } diff --git a/android/app/src/com/android/bluetooth/BluetoothObexTransport.java b/android/app/src/com/android/bluetooth/BluetoothObexTransport.java index 3c57ec1600..d101f1736e 100644 --- a/android/app/src/com/android/bluetooth/BluetoothObexTransport.java +++ b/android/app/src/com/android/bluetooth/BluetoothObexTransport.java @@ -18,7 +18,6 @@ package com.android.bluetooth; import android.annotation.SuppressLint; import android.bluetooth.BluetoothSocket; -import com.android.bluetooth.flags.Flags; import com.android.obex.ObexTransport; import java.io.DataInputStream; @@ -112,10 +111,7 @@ public class BluetoothObexTransport implements ObexTransport { if (mSocket == null) { return null; } - String identityAddress = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(mSocket.getRemoteDevice()) - : mSocket.getRemoteDevice().getIdentityAddress(); + String identityAddress = Utils.getBrEdrAddress(mSocket.getRemoteDevice()); return mSocket.getConnectionType() == BluetoothSocket.TYPE_RFCOMM ? identityAddress : mSocket.getRemoteDevice().getAddress(); diff --git a/android/app/src/com/android/bluetooth/Utils.java b/android/app/src/com/android/bluetooth/Utils.java index ce23339f0b..3a681bb7e7 100644 --- a/android/app/src/com/android/bluetooth/Utils.java +++ b/android/app/src/com/android/bluetooth/Utils.java @@ -624,6 +624,13 @@ public final class Utils { return checkPermissionForDataDelivery(context, BLUETOOTH_CONNECT, source, message); } + @SuppressLint("AndroidFrameworkRequiresPermission") // This method enforce the permission + @RequiresPermission(BLUETOOTH_CONNECT) + public static boolean checkConnectPermissionForDataDelivery( + Context context, AttributionSource source, String tag, String method) { + return checkConnectPermissionForDataDelivery(context, source, tag + "." + method + "()"); + } + /** * Returns true if the BLUETOOTH_SCAN permission is granted for the calling app. Returns false * if the result is a soft denial. Throws SecurityException if the result is a hard denial. @@ -646,8 +653,9 @@ public final class Utils { @SuppressLint("AndroidFrameworkRequiresPermission") // This method enforce the permission @RequiresPermission(BLUETOOTH_SCAN) public static boolean checkScanPermissionForDataDelivery( - Context context, AttributionSource source, String message) { - return checkPermissionForDataDelivery(context, BLUETOOTH_SCAN, source, message); + Context context, AttributionSource source, String tag, String method) { + return checkPermissionForDataDelivery( + context, BLUETOOTH_SCAN, source, tag + "." + method + "()"); } /** diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java b/android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java index fe74b2facd..688f57ce8a 100644 --- a/android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java +++ b/android/app/src/com/android/bluetooth/a2dp/A2dpNativeInterface.java @@ -29,8 +29,6 @@ import android.bluetooth.BluetoothCodecType; import android.bluetooth.BluetoothDevice; import com.android.bluetooth.Utils; -import com.android.bluetooth.btservice.AdapterService; -import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Native; @@ -41,15 +39,12 @@ import java.util.List; public class A2dpNativeInterface { private static final String TAG = A2dpNativeInterface.class.getSimpleName(); - private final AdapterService mAdapterService; @Native private final A2dpNativeCallback mNativeCallback; private BluetoothCodecType[] mSupportedCodecTypes; @VisibleForTesting - A2dpNativeInterface( - @NonNull AdapterService adapterService, @NonNull A2dpNativeCallback nativeCallback) { - mAdapterService = requireNonNull(adapterService); + A2dpNativeInterface(@NonNull A2dpNativeCallback nativeCallback) { mNativeCallback = requireNonNull(nativeCallback); } @@ -132,15 +127,11 @@ public class A2dpNativeInterface { return setCodecConfigPreferenceNative(getByteAddress(device), codecConfigArray); } - private byte[] getByteAddress(BluetoothDevice device) { + private static byte[] getByteAddress(BluetoothDevice device) { if (device == null) { return Utils.getBytesFromAddress("00:00:00:00:00:00"); } - if (Flags.identityAddressNullIfNotKnown()) { - return Utils.getByteBrEdrAddress(device); - } else { - return mAdapterService.getByteIdentityAddress(device); - } + return Utils.getByteBrEdrAddress(device); } private native void initNative( diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java index 9481146d61..6633e4e2ea 100644 --- a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java +++ b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java @@ -26,8 +26,6 @@ import static android.bluetooth.BluetoothProfile.STATE_CONNECTING; import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTING; -import static com.android.bluetooth.Utils.checkCallerTargetSdk; - import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNullElseGet; @@ -44,15 +42,12 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; import android.bluetooth.BufferConstraints; -import android.bluetooth.IBluetoothA2dp; import android.companion.CompanionDeviceManager; -import android.content.AttributionSource; import android.content.Intent; import android.media.AudioDeviceCallback; import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.BluetoothProfileConnectionInfo; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -63,7 +58,6 @@ import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.ActiveDeviceManager; import com.android.bluetooth.btservice.AdapterService; -import com.android.bluetooth.btservice.MetricsLogger; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.ServiceFactory; import com.android.bluetooth.btservice.storage.DatabaseManager; @@ -73,7 +67,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @@ -132,7 +125,6 @@ public class A2dpService extends ProfileService { nativeInterface, () -> new A2dpNativeInterface( - adapterService, new A2dpNativeCallback(adapterService, this))); mDatabaseManager = requireNonNull(mAdapterService.getDatabase()); mAudioManager = requireNonNull(getSystemService(AudioManager.class)); @@ -168,7 +160,7 @@ public class A2dpService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new BluetoothA2dpBinder(this); + return new A2dpServiceBinder(this); } @Override @@ -203,6 +195,10 @@ public class A2dpService extends ProfileService { mHandler.removeCallbacksAndMessages(null); } + CompanionDeviceManager getCompanionDeviceManager() { + return mCompanionDeviceManager; + } + public static synchronized A2dpService getA2dpService() { if (sA2dpService == null) { Log.w(TAG, "getA2dpService(): service is null"); @@ -1001,13 +997,7 @@ public class A2dpService extends ProfileService { return null; } Log.d(TAG, "Creating a new state machine for " + device); - sm = - new A2dpStateMachine( - this, - device, - mNativeInterface, - mA2dpOffloadEnabled, - mLooper); + sm = new A2dpStateMachine(this, device, mNativeInterface, mA2dpOffloadEnabled, mLooper); mStateMachines.put(device, sm); return sm; } @@ -1345,320 +1335,6 @@ public class A2dpService extends ProfileService { : null; } - /** Binder object: must be a static class or memory leak may occur. */ - @VisibleForTesting - static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub implements IProfileServiceBinder { - private A2dpService mService; - - @RequiresPermission(BLUETOOTH_CONNECT) - private A2dpService getServiceAndEnforceConnect(AttributionSource source) { - // Cache mService because it can change while getService is called - A2dpService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - return service; - } - - private A2dpService getService() { - // Cache mService because it can change while getService is called - A2dpService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG)) { - return null; - } - return service; - } - - BluetoothA2dpBinder(A2dpService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @Override - public boolean connect(BluetoothDevice device, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - return service.connect(device); - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - return service.disconnect(device); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } - - @Override - public boolean setActiveDevice(BluetoothDevice device, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - if (device == null) { - return service.removeActiveDevice(false); - } else { - return service.setActiveDevice(device); - } - } - - @Override - public BluetoothDevice getActiveDevice(AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return null; - } - - return service.getActiveDevice(); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectionPolicy(device); - } - - @Override - public void setAvrcpAbsoluteVolume(int volume, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.setAvrcpAbsoluteVolume(volume); - } - - @Override - public boolean isA2dpPlaying(BluetoothDevice device, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - return service.isA2dpPlaying(device); - } - - @Override - public List<BluetoothCodecType> getSupportedCodecTypes() { - A2dpService service = getService(); - if (service == null) { - return Collections.emptyList(); - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getSupportedCodecTypes(); - } - - @Override - public BluetoothCodecStatus getCodecStatus( - BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return null; - } - - Utils.enforceCdmAssociationIfNotBluetoothPrivileged( - service, service.mCompanionDeviceManager, source, device); - - return service.getCodecStatus(device); - } - - @Override - public void setCodecConfigPreference( - BluetoothDevice device, - BluetoothCodecConfig codecConfig, - AttributionSource source) { - requireNonNull(device); - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - Utils.enforceCdmAssociationIfNotBluetoothPrivileged( - service, service.mCompanionDeviceManager, source, device); - - service.setCodecConfigPreference(device, codecConfig); - } - - @Override - public void enableOptionalCodecs(BluetoothDevice device, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - if (checkCallerTargetSdk( - mService, source.getPackageName(), Build.VERSION_CODES.TIRAMISU)) { - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - } - service.enableOptionalCodecs(device); - } - - @Override - public void disableOptionalCodecs(BluetoothDevice device, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - if (checkCallerTargetSdk( - mService, source.getPackageName(), Build.VERSION_CODES.TIRAMISU)) { - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - } - service.disableOptionalCodecs(device); - } - - @Override - public int isOptionalCodecsSupported(BluetoothDevice device, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN; - } - - if (checkCallerTargetSdk( - mService, source.getPackageName(), Build.VERSION_CODES.TIRAMISU)) { - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - } - return service.getSupportsOptionalCodecs(device); - } - - @Override - public int isOptionalCodecsEnabled(BluetoothDevice device, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN; - } - - if (checkCallerTargetSdk( - mService, source.getPackageName(), Build.VERSION_CODES.TIRAMISU)) { - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - } - return service.getOptionalCodecsEnabled(device); - } - - @Override - public void setOptionalCodecsEnabled( - BluetoothDevice device, int value, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - if (checkCallerTargetSdk( - mService, source.getPackageName(), Build.VERSION_CODES.TIRAMISU)) { - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - } - service.setOptionalCodecsEnabled(device, value); - } - - @Override - public int getDynamicBufferSupport(AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_NONE; - } - - return service.getDynamicBufferSupport(); - } - - @Override - public BufferConstraints getBufferConstraints(AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return null; - } - - return service.getBufferConstraints(); - } - - @Override - public boolean setBufferLengthMillis(int codec, int value, AttributionSource source) { - A2dpService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - return service.setBufferLengthMillis(codec, value); - } - } - @Override public void dump(StringBuilder sb) { super.dump(sb); diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpServiceBinder.java b/android/app/src/com/android/bluetooth/a2dp/A2dpServiceBinder.java new file mode 100644 index 0000000000..da8aaae42a --- /dev/null +++ b/android/app/src/com/android/bluetooth/a2dp/A2dpServiceBinder.java @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.a2dp; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import static com.android.bluetooth.Utils.checkCallerTargetSdk; + +import static java.util.Objects.requireNonNull; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothCodecConfig; +import android.bluetooth.BluetoothCodecStatus; +import android.bluetooth.BluetoothCodecType; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BufferConstraints; +import android.bluetooth.IBluetoothA2dp; +import android.content.AttributionSource; +import android.os.Build; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +class A2dpServiceBinder extends IBluetoothA2dp.Stub implements IProfileServiceBinder { + private static final String TAG = A2dpServiceBinder.class.getSimpleName(); + + private A2dpService mService; + + A2dpServiceBinder(A2dpService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + private A2dpService getService() { + A2dpService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG)) { + return null; + } + return service; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private A2dpService getServiceAndEnforceConnect(AttributionSource source) { + A2dpService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + return service; + } + + @Override + public boolean connect(BluetoothDevice device, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + return service.connect(device); + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + return service.disconnect(device); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public boolean setActiveDevice(BluetoothDevice device, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + if (device == null) { + return service.removeActiveDevice(false); + } else { + return service.setActiveDevice(device); + } + } + + @Override + public BluetoothDevice getActiveDevice(AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return null; + } + return service.getActiveDevice(); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionPolicy(device); + } + + @Override + public void setAvrcpAbsoluteVolume(int volume, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setAvrcpAbsoluteVolume(volume); + } + + @Override + public boolean isA2dpPlaying(BluetoothDevice device, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + return service.isA2dpPlaying(device); + } + + @Override + public List<BluetoothCodecType> getSupportedCodecTypes() { + A2dpService service = getService(); + if (service == null) { + return Collections.emptyList(); + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getSupportedCodecTypes(); + } + + @Override + public BluetoothCodecStatus getCodecStatus(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return null; + } + + Utils.enforceCdmAssociationIfNotBluetoothPrivileged( + service, service.getCompanionDeviceManager(), source, device); + + return service.getCodecStatus(device); + } + + @Override + public void setCodecConfigPreference( + BluetoothDevice device, BluetoothCodecConfig codecConfig, AttributionSource source) { + requireNonNull(device); + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + Utils.enforceCdmAssociationIfNotBluetoothPrivileged( + service, service.getCompanionDeviceManager(), source, device); + + service.setCodecConfigPreference(device, codecConfig); + } + + @Override + public void enableOptionalCodecs(BluetoothDevice device, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + if (checkCallerTargetSdk(mService, source.getPackageName(), Build.VERSION_CODES.TIRAMISU)) { + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + } + service.enableOptionalCodecs(device); + } + + @Override + public void disableOptionalCodecs(BluetoothDevice device, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + if (checkCallerTargetSdk(mService, source.getPackageName(), Build.VERSION_CODES.TIRAMISU)) { + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + } + service.disableOptionalCodecs(device); + } + + @Override + public int isOptionalCodecsSupported(BluetoothDevice device, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN; + } + + if (checkCallerTargetSdk(mService, source.getPackageName(), Build.VERSION_CODES.TIRAMISU)) { + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + } + return service.getSupportsOptionalCodecs(device); + } + + @Override + public int isOptionalCodecsEnabled(BluetoothDevice device, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN; + } + + if (checkCallerTargetSdk(mService, source.getPackageName(), Build.VERSION_CODES.TIRAMISU)) { + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + } + return service.getOptionalCodecsEnabled(device); + } + + @Override + public void setOptionalCodecsEnabled( + BluetoothDevice device, int value, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + if (checkCallerTargetSdk(mService, source.getPackageName(), Build.VERSION_CODES.TIRAMISU)) { + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + } + service.setOptionalCodecsEnabled(device, value); + } + + @Override + public int getDynamicBufferSupport(AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_NONE; + } + + return service.getDynamicBufferSupport(); + } + + @Override + public BufferConstraints getBufferConstraints(AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return null; + } + + return service.getBufferConstraints(); + } + + @Override + public boolean setBufferLengthMillis(int codec, int value, AttributionSource source) { + A2dpService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + return service.setBufferLengthMillis(codec, value); + } +} diff --git a/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface.java b/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface.java index e3b4c400a3..6822e4e734 100644 --- a/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface.java +++ b/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface.java @@ -23,7 +23,6 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; -import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -78,14 +77,6 @@ public class A2dpSinkNativeInterface { return mAdapterService.getDeviceFromByte(address); } - private byte[] getByteAddress(BluetoothDevice device) { - if (Flags.identityAddressNullIfNotKnown()) { - return Utils.getByteBrEdrAddress(device); - } else { - return mAdapterService.getByteIdentityAddress(device); - } - } - /** * Initiates an A2DP connection to a remote device. * @@ -93,7 +84,7 @@ public class A2dpSinkNativeInterface { * @return true on success, otherwise false. */ public boolean connectA2dpSink(BluetoothDevice device) { - return connectA2dpNative(getByteAddress(device)); + return connectA2dpNative(Utils.getByteBrEdrAddress(device)); } /** @@ -103,7 +94,7 @@ public class A2dpSinkNativeInterface { * @return true on success, otherwise false. */ public boolean disconnectA2dpSink(BluetoothDevice device) { - return disconnectA2dpNative(getByteAddress(device)); + return disconnectA2dpNative(Utils.getByteBrEdrAddress(device)); } /** @@ -120,7 +111,7 @@ public class A2dpSinkNativeInterface { // Translate to byte address for JNI. Use an all 0 MAC for no active device byte[] address = null; if (device != null) { - address = getByteAddress(device); + address = Utils.getByteBrEdrAddress(device); } else { address = Utils.getBytesFromAddress("00:00:00:00:00:00"); } diff --git a/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java b/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java index 10b9249bad..6750a9a9c8 100644 --- a/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java +++ b/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java @@ -13,30 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.bluetooth.a2dpsink; -import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; -import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTING; import static java.util.Objects.requireNonNull; -import android.annotation.RequiresPermission; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAudioConfig; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; -import android.bluetooth.IBluetoothA2dpSink; -import android.content.AttributionSource; import android.os.Looper; import android.sysprop.BluetoothProperties; import android.util.Log; -import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.storage.DatabaseManager; @@ -45,7 +39,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -177,136 +170,6 @@ public class A2dpSinkService extends ProfileService { return new A2dpSinkServiceBinder(this); } - // Binder object: Must be static class or memory leak may occur - @VisibleForTesting - static class A2dpSinkServiceBinder extends IBluetoothA2dpSink.Stub - implements IProfileServiceBinder { - private A2dpSinkService mService; - - A2dpSinkServiceBinder(A2dpSinkService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private A2dpSinkService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - A2dpSinkService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - return service; - } - - @Override - public boolean connect(BluetoothDevice device, AttributionSource source) { - A2dpSinkService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.connect(device); - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - A2dpSinkService service = getService(source); - if (service == null) { - return false; - } - return service.disconnect(device); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - A2dpSinkService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - A2dpSinkService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - A2dpSinkService service = getService(source); - if (service == null) { - return STATE_DISCONNECTED; - } - return service.getConnectionState(device); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - A2dpSinkService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - A2dpSinkService service = getService(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectionPolicy(device); - } - - @Override - public boolean isA2dpPlaying(BluetoothDevice device, AttributionSource source) { - A2dpSinkService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.isA2dpPlaying(device); - } - - @Override - public BluetoothAudioConfig getAudioConfig( - BluetoothDevice device, AttributionSource source) { - A2dpSinkService service = getService(source); - if (service == null) { - return null; - } - return service.getAudioConfig(device); - } - } - /* Generic Profile Code */ /** diff --git a/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkServiceBinder.java b/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkServiceBinder.java new file mode 100644 index 0000000000..851e48a286 --- /dev/null +++ b/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkServiceBinder.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.a2dpsink; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothAudioConfig; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IBluetoothA2dpSink; +import android.content.AttributionSource; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +class A2dpSinkServiceBinder extends IBluetoothA2dpSink.Stub implements IProfileServiceBinder { + private static final String TAG = A2dpSinkServiceBinder.class.getSimpleName(); + + private A2dpSinkService mService; + + A2dpSinkServiceBinder(A2dpSinkService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private A2dpSinkService getService(AttributionSource source) { + A2dpSinkService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + return service; + } + + @Override + public boolean connect(BluetoothDevice device, AttributionSource source) { + A2dpSinkService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.connect(device); + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + A2dpSinkService service = getService(source); + if (service == null) { + return false; + } + return service.disconnect(device); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + A2dpSinkService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + A2dpSinkService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + A2dpSinkService service = getService(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + A2dpSinkService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + A2dpSinkService service = getService(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionPolicy(device); + } + + @Override + public boolean isA2dpPlaying(BluetoothDevice device, AttributionSource source) { + A2dpSinkService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.isA2dpPlaying(device); + } + + @Override + public BluetoothAudioConfig getAudioConfig(BluetoothDevice device, AttributionSource source) { + A2dpSinkService service = getService(source); + if (service == null) { + return null; + } + return service.getAudioConfig(device); + } +} diff --git a/android/app/src/com/android/bluetooth/a2dpsink/OWNERS b/android/app/src/com/android/bluetooth/a2dpsink/OWNERS deleted file mode 100644 index ecd59038a1..0000000000 --- a/android/app/src/com/android/bluetooth/a2dpsink/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_automotive diff --git a/android/app/src/com/android/bluetooth/audio_util/MediaBrowserWrapper.java b/android/app/src/com/android/bluetooth/audio_util/MediaBrowserWrapper.java index 517e810d8a..3c235cce76 100644 --- a/android/app/src/com/android/bluetooth/audio_util/MediaBrowserWrapper.java +++ b/android/app/src/com/android/bluetooth/audio_util/MediaBrowserWrapper.java @@ -197,7 +197,7 @@ class MediaBrowserWrapper { mSubscribedIds.put( rootId, new ArrayList<>(Arrays.asList(callback))); mWrappedBrowser.subscribe( - rootId, new BrowserSubscriptionCallback(mediaId)); + rootId, new BrowserSubscriptionCallback(rootId)); }); } else { mSubscribedIds.put(mediaId, new ArrayList<>(Arrays.asList(callback))); diff --git a/android/app/src/com/android/bluetooth/avrcp/AvrcpNativeInterface.java b/android/app/src/com/android/bluetooth/avrcp/AvrcpNativeInterface.java index 720ce84dd8..85d1043023 100644 --- a/android/app/src/com/android/bluetooth/avrcp/AvrcpNativeInterface.java +++ b/android/app/src/com/android/bluetooth/avrcp/AvrcpNativeInterface.java @@ -28,7 +28,6 @@ import com.android.bluetooth.audio_util.PlayStatus; import com.android.bluetooth.audio_util.PlayerInfo; import com.android.bluetooth.audio_util.PlayerSettingsManager.PlayerSettingsValues; import com.android.bluetooth.btservice.AdapterService; -import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -93,10 +92,7 @@ public class AvrcpNativeInterface { } void setBipClientStatus(BluetoothDevice device, boolean connected) { - String identityAddress = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(device) - : mAdapterService.getIdentityAddress(device.getAddress()); + String identityAddress = Utils.getBrEdrAddress(device); setBipClientStatusNative(identityAddress, connected); } @@ -237,10 +233,7 @@ public class AvrcpNativeInterface { } boolean disconnectDevice(BluetoothDevice device) { - String identityAddress = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(device) - : mAdapterService.getIdentityAddress(device.getAddress()); + String identityAddress = Utils.getBrEdrAddress(device); d("disconnectDevice: identityAddress=" + identityAddress); return disconnectDeviceNative(identityAddress); } @@ -278,10 +271,7 @@ public class AvrcpNativeInterface { void sendVolumeChanged(BluetoothDevice device, int volume) { d("sendVolumeChanged: volume=" + volume); - String identityAddress = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(device) - : mAdapterService.getIdentityAddress(device.getAddress()); + String identityAddress = Utils.getBrEdrAddress(device); sendVolumeChangedNative(identityAddress, volume); } diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java index 4551f320da..c4ef6a2437 100644 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java @@ -16,19 +16,14 @@ package com.android.bluetooth.avrcpcontroller; -import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; import static android.bluetooth.BluetoothProfile.STATE_CONNECTING; import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; import static java.util.Objects.requireNonNull; -import android.annotation.RequiresPermission; import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothAvrcpPlayerSettings; import android.bluetooth.BluetoothDevice; -import android.bluetooth.IBluetoothAvrcpController; -import android.content.AttributionSource; import android.content.Intent; import android.media.AudioManager; import android.support.v4.media.MediaBrowserCompat.MediaItem; @@ -46,7 +41,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; @@ -368,90 +362,6 @@ public class AvrcpControllerService extends ProfileService { return new AvrcpControllerServiceBinder(this); } - // Binder object: Must be static class or memory leak may occur - @VisibleForTesting - static class AvrcpControllerServiceBinder extends IBluetoothAvrcpController.Stub - implements IProfileServiceBinder { - private AvrcpControllerService mService; - - AvrcpControllerServiceBinder(AvrcpControllerService service) { - mService = service; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private AvrcpControllerService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - AvrcpControllerService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - return service; - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - AvrcpControllerService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - AvrcpControllerService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - AvrcpControllerService service = getService(source); - if (service == null) { - return STATE_DISCONNECTED; - } - return service.getConnectionState(device); - } - - @Override - public void sendGroupNavigationCmd( - BluetoothDevice device, int keyCode, int keyState, AttributionSource source) { - getService(source); - Log.w(TAG, "sendGroupNavigationCmd not implemented"); - } - - @Override - public void setPlayerApplicationSetting( - BluetoothAvrcpPlayerSettings settings, AttributionSource source) { - getService(source); - Log.w(TAG, "setPlayerApplicationSetting not implemented"); - } - - @Override - public BluetoothAvrcpPlayerSettings getPlayerSettings( - BluetoothDevice device, AttributionSource source) { - getService(source); - Log.w(TAG, "getPlayerSettings not implemented"); - return null; - } - } - // Called by JNI when a device has connected or disconnected. @VisibleForTesting synchronized void onConnectionStateChanged( diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerServiceBinder.java b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerServiceBinder.java new file mode 100644 index 0000000000..105e9a8709 --- /dev/null +++ b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerServiceBinder.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.avrcpcontroller; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothAvrcpPlayerSettings; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IBluetoothAvrcpController; +import android.content.AttributionSource; +import android.util.Log; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +class AvrcpControllerServiceBinder extends IBluetoothAvrcpController.Stub + implements IProfileServiceBinder { + private static final String TAG = AvrcpControllerServiceBinder.class.getSimpleName(); + + private AvrcpControllerService mService; + + AvrcpControllerServiceBinder(AvrcpControllerService service) { + mService = service; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private AvrcpControllerService getService(AttributionSource source) { + AvrcpControllerService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + return service; + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + AvrcpControllerService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + AvrcpControllerService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + AvrcpControllerService service = getService(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public void sendGroupNavigationCmd( + BluetoothDevice device, int keyCode, int keyState, AttributionSource source) { + getService(source); + Log.w(TAG, "sendGroupNavigationCmd not implemented"); + } + + @Override + public void setPlayerApplicationSetting( + BluetoothAvrcpPlayerSettings settings, AttributionSource source) { + getService(source); + Log.w(TAG, "setPlayerApplicationSetting not implemented"); + } + + @Override + public BluetoothAvrcpPlayerSettings getPlayerSettings( + BluetoothDevice device, AttributionSource source) { + getService(source); + Log.w(TAG, "getPlayerSettings not implemented"); + return null; + } +} diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/OWNERS b/android/app/src/com/android/bluetooth/avrcpcontroller/OWNERS deleted file mode 100644 index ecd59038a1..0000000000 --- a/android/app/src/com/android/bluetooth/avrcpcontroller/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_automotive diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java index 2b2b495ce4..42528676b4 100644 --- a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java +++ b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java @@ -16,9 +16,6 @@ package com.android.bluetooth.bass_client; -import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; -import static android.Manifest.permission.BLUETOOTH_SCAN; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; @@ -36,7 +33,6 @@ import static com.android.bluetooth.flags.Flags.leaudioSortScansToSyncByFails; import static java.util.Objects.requireNonNull; -import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; @@ -50,7 +46,6 @@ import android.bluetooth.BluetoothLeBroadcastSubgroup; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothStatusCodes; import android.bluetooth.BluetoothUuid; -import android.bluetooth.IBluetoothLeBroadcastAssistant; import android.bluetooth.IBluetoothLeBroadcastAssistantCallback; import android.bluetooth.le.IScannerCallback; import android.bluetooth.le.PeriodicAdvertisingCallback; @@ -60,7 +55,6 @@ import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; -import android.content.AttributionSource; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -737,7 +731,7 @@ public class BassClientService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new BluetoothLeBroadcastAssistantBinder(this); + return new BassClientServiceBinder(this); } @Override @@ -4829,234 +4823,4 @@ public class BassClientService extends ProfileService { sEventLogger.dump(sb); sb.append("\n"); } - - /** Binder object: must be a static class or memory leak may occur */ - @VisibleForTesting - static class BluetoothLeBroadcastAssistantBinder extends IBluetoothLeBroadcastAssistant.Stub - implements IProfileServiceBinder { - BassClientService mService; - - BluetoothLeBroadcastAssistantBinder(BassClientService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) - private BassClientService getServiceAndEnforceConnect(AttributionSource source) { - // Cache mService because it can change while getService is called - BassClientService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service; - } - - @RequiresPermission(allOf = {BLUETOOTH_SCAN, BLUETOOTH_PRIVILEGED}) - private BassClientService getServiceAndEnforceScan(AttributionSource source) { - // Cache mService because it can change while getService is called - BassClientService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkScanPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service; - } - - @Override - public int getConnectionState(BluetoothDevice sink, AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return STATE_DISCONNECTED; - } - return service.getConnectionState(sink); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return Collections.emptyList(); - } - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return Collections.emptyList(); - } - return service.getConnectedDevices(); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return false; - } - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return CONNECTION_POLICY_FORBIDDEN; - } - return service.getConnectionPolicy(device); - } - - @Override - public void registerCallback( - IBluetoothLeBroadcastAssistantCallback cb, AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return; - } - service.registerCallback(cb); - } - - @Override - public void unregisterCallback( - IBluetoothLeBroadcastAssistantCallback cb, AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return; - } - service.unregisterCallback(cb); - } - - @Override - public void startSearchingForSources(List<ScanFilter> filters, AttributionSource source) { - BassClientService service = getServiceAndEnforceScan(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return; - } - service.startSearchingForSources(filters); - } - - @Override - public void stopSearchingForSources(AttributionSource source) { - BassClientService service = getServiceAndEnforceScan(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return; - } - service.stopSearchingForSources(); - } - - @Override - public boolean isSearchInProgress(AttributionSource source) { - BassClientService service = getServiceAndEnforceScan(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return false; - } - return service.isSearchInProgress(); - } - - @Override - public void addSource( - BluetoothDevice sink, - BluetoothLeBroadcastMetadata sourceMetadata, - boolean isGroupOp, - AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return; - } - service.addSource(sink, sourceMetadata, isGroupOp); - } - - @Override - public void modifySource( - BluetoothDevice sink, - int sourceId, - BluetoothLeBroadcastMetadata updatedMetadata, - AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return; - } - service.modifySource(sink, sourceId, updatedMetadata); - } - - @Override - public void removeSource(BluetoothDevice sink, int sourceId, AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return; - } - service.removeSource(sink, sourceId); - } - - @Override - public List<BluetoothLeBroadcastReceiveState> getAllSources( - BluetoothDevice sink, AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return Collections.emptyList(); - } - return service.getAllSources(sink); - } - - @Override - public int getMaximumSourceCapacity(BluetoothDevice sink, AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return 0; - } - return service.getMaximumSourceCapacity(sink); - } - - @Override - public BluetoothLeBroadcastMetadata getSourceMetadata( - BluetoothDevice sink, int sourceId, AttributionSource source) { - BassClientService service = getServiceAndEnforceConnect(source); - if (service == null) { - Log.e(TAG, "Service is null"); - return null; - } - return service.getSourceMetadata(sink, sourceId); - } - } } diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientServiceBinder.java b/android/app/src/com/android/bluetooth/bass_client/BassClientServiceBinder.java new file mode 100644 index 0000000000..d319e6ed47 --- /dev/null +++ b/android/app/src/com/android/bluetooth/bass_client/BassClientServiceBinder.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.bass_client; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.Manifest.permission.BLUETOOTH_SCAN; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; +import android.bluetooth.IBluetoothLeBroadcastAssistant; +import android.bluetooth.IBluetoothLeBroadcastAssistantCallback; +import android.bluetooth.le.ScanFilter; +import android.content.AttributionSource; +import android.util.Log; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +class BassClientServiceBinder extends IBluetoothLeBroadcastAssistant.Stub + implements IProfileServiceBinder { + private static final String TAG = BassClientServiceBinder.class.getSimpleName(); + + private BassClientService mService; + + BassClientServiceBinder(BassClientService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) + private BassClientService getServiceAndEnforceConnect(AttributionSource source) { + BassClientService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + return service; + } + + @RequiresPermission(allOf = {BLUETOOTH_SCAN, BLUETOOTH_PRIVILEGED}) + private BassClientService getServiceAndEnforceScan(AttributionSource source) { + BassClientService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkScanPermissionForDataDelivery( + service, source, TAG, "getServiceAndEnforceScan")) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + return service; + } + + @Override + public int getConnectionState(BluetoothDevice sink, AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return STATE_DISCONNECTED; + } + return service.getConnectionState(sink); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return CONNECTION_POLICY_FORBIDDEN; + } + return service.getConnectionPolicy(device); + } + + @Override + public void registerCallback( + IBluetoothLeBroadcastAssistantCallback cb, AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return; + } + service.registerCallback(cb); + } + + @Override + public void unregisterCallback( + IBluetoothLeBroadcastAssistantCallback cb, AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return; + } + service.unregisterCallback(cb); + } + + @Override + public void startSearchingForSources(List<ScanFilter> filters, AttributionSource source) { + BassClientService service = getServiceAndEnforceScan(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return; + } + service.startSearchingForSources(filters); + } + + @Override + public void stopSearchingForSources(AttributionSource source) { + BassClientService service = getServiceAndEnforceScan(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return; + } + service.stopSearchingForSources(); + } + + @Override + public boolean isSearchInProgress(AttributionSource source) { + BassClientService service = getServiceAndEnforceScan(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return false; + } + return service.isSearchInProgress(); + } + + @Override + public void addSource( + BluetoothDevice sink, + BluetoothLeBroadcastMetadata sourceMetadata, + boolean isGroupOp, + AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return; + } + service.addSource(sink, sourceMetadata, isGroupOp); + } + + @Override + public void modifySource( + BluetoothDevice sink, + int sourceId, + BluetoothLeBroadcastMetadata updatedMetadata, + AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return; + } + service.modifySource(sink, sourceId, updatedMetadata); + } + + @Override + public void removeSource(BluetoothDevice sink, int sourceId, AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return; + } + service.removeSource(sink, sourceId); + } + + @Override + public List<BluetoothLeBroadcastReceiveState> getAllSources( + BluetoothDevice sink, AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return Collections.emptyList(); + } + return service.getAllSources(sink); + } + + @Override + public int getMaximumSourceCapacity(BluetoothDevice sink, AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return 0; + } + return service.getMaximumSourceCapacity(sink); + } + + @Override + public BluetoothLeBroadcastMetadata getSourceMetadata( + BluetoothDevice sink, int sourceId, AttributionSource source) { + BassClientService service = getServiceAndEnforceConnect(source); + if (service == null) { + Log.e(TAG, "Service is null"); + return null; + } + return service.getSourceMetadata(sink, sourceId); + } +} diff --git a/android/app/src/com/android/bluetooth/bass_client/OWNERS b/android/app/src/com/android/bluetooth/bass_client/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/app/src/com/android/bluetooth/bass_client/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java b/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java index bd483f5925..013c799af7 100644 --- a/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java +++ b/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java @@ -55,7 +55,6 @@ import androidx.annotation.VisibleForTesting; import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; -import com.android.bluetooth.flags.Flags; import com.android.modules.utils.build.SdkLevel; import java.io.FileDescriptor; @@ -531,10 +530,7 @@ class AdapterProperties { void cleanupPrevBondRecordsFor(BluetoothDevice device) { String address = device.getAddress(); - String identityAddress = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(device, mService) - : mService.getIdentityAddress(address); + String identityAddress = Utils.getBrEdrAddress(device, mService); int deviceType = mRemoteDevices.getDeviceProperties(device).getDeviceType(); debugLog("cleanupPrevBondRecordsFor: " + device + ", device type: " + deviceType); if (identityAddress == null) { @@ -547,10 +543,7 @@ class AdapterProperties { for (BluetoothDevice existingDevice : mBondedDevices) { String existingAddress = existingDevice.getAddress(); - String existingIdentityAddress = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(existingDevice, mService) - : mService.getIdentityAddress(existingAddress); + String existingIdentityAddress = Utils.getBrEdrAddress(existingDevice, mService); int existingDeviceType = mRemoteDevices.getDeviceProperties(existingDevice).getDeviceType(); @@ -1100,10 +1093,7 @@ class AdapterProperties { StringBuilder sb = new StringBuilder(); for (BluetoothDevice device : mBondedDevices) { String address = device.getAddress(); - String brEdrAddress = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(device) - : mService.getIdentityAddress(address); + String brEdrAddress = Utils.getBrEdrAddress(device); if (brEdrAddress.equals(address)) { writer.println( " " diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java index eff7a6e132..182e75cceb 100644 --- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java +++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java @@ -20,16 +20,12 @@ package com.android.bluetooth.btservice; import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.Manifest.permission.BLUETOOTH_SCAN; -import static android.Manifest.permission.DUMP; -import static android.Manifest.permission.LOCAL_MAC_ADDRESS; -import static android.Manifest.permission.MODIFY_PHONE_STATE; import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE; import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE; import static android.bluetooth.BluetoothAdapter.nameForState; import static android.bluetooth.BluetoothDevice.BATTERY_LEVEL_UNKNOWN; import static android.bluetooth.BluetoothDevice.BOND_NONE; -import static android.bluetooth.BluetoothDevice.TRANSPORT_AUTO; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; @@ -42,9 +38,6 @@ import static android.bluetooth.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; -import static com.android.bluetooth.ChangeIds.ENFORCE_CONNECT; -import static com.android.bluetooth.Utils.callerIsSystem; -import static com.android.bluetooth.Utils.callerIsSystemOrActiveOrManagedUser; import static com.android.bluetooth.Utils.getBytesFromAddress; import static com.android.bluetooth.Utils.isDualModeAudioEnabled; import static com.android.bluetooth.Utils.isPackageNameAccurate; @@ -60,7 +53,6 @@ import android.app.AppOpsManager; import android.app.PendingIntent; import android.app.Service; import android.app.admin.DevicePolicyManager; -import android.app.compat.CompatChanges; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.BluetoothAdapter; @@ -72,7 +64,6 @@ import android.bluetooth.BluetoothFrameworkInitializer; import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothMap; import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothProtoEnums; import android.bluetooth.BluetoothQualityReport; import android.bluetooth.BluetoothSap; import android.bluetooth.BluetoothServerSocket; @@ -82,16 +73,12 @@ import android.bluetooth.BluetoothStatusCodes; import android.bluetooth.BluetoothUtils; import android.bluetooth.BluetoothUuid; import android.bluetooth.BufferConstraints; -import android.bluetooth.IBluetooth; -import android.bluetooth.IBluetoothActivityEnergyInfoListener; import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothConnectionCallback; -import android.bluetooth.IBluetoothHciVendorSpecificCallback; import android.bluetooth.IBluetoothMetadataListener; import android.bluetooth.IBluetoothOobDataCallback; import android.bluetooth.IBluetoothPreferredAudioProfilesCallback; import android.bluetooth.IBluetoothQualityReportReadyCallback; -import android.bluetooth.IBluetoothSocketManager; import android.bluetooth.IncomingRfcommSocketInfo; import android.bluetooth.OobData; import android.bluetooth.UidTraffic; @@ -115,7 +102,6 @@ import android.os.Message; import android.os.ParcelUuid; import android.os.Parcelable; import android.os.PowerManager; -import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; @@ -125,7 +111,6 @@ import android.provider.DeviceConfig; import android.provider.Settings; import android.sysprop.BluetoothProperties; import android.text.TextUtils; -import android.util.Base64; import android.util.Log; import android.util.Pair; import android.util.SparseArray; @@ -172,16 +157,10 @@ import com.android.bluetooth.telephony.BluetoothInCallService; import com.android.bluetooth.vc.VolumeControlService; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.modules.expresslog.Counter; import com.android.modules.utils.BackgroundThread; import com.android.modules.utils.BytesMatcher; -import libcore.util.SneakyThrow; - -import com.google.protobuf.InvalidProtocolBufferException; - import java.io.FileDescriptor; -import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.FileVisitResult; @@ -195,7 +174,6 @@ import java.time.Instant; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -206,14 +184,12 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Pattern; -import java.util.stream.Collectors; public class AdapterService extends Service { private static final String TAG = @@ -225,9 +201,6 @@ public class AdapterService extends Service { private static final int MESSAGE_PREFERRED_AUDIO_PROFILES_AUDIO_FRAMEWORK_TIMEOUT = 4; private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 100; - private static final int MIN_ADVT_INSTANCES_FOR_MA = 5; - private static final int MIN_OFFLOADED_FILTERS = 10; - private static final int MIN_OFFLOADED_SCAN_STORAGE_BYTES = 1024; private static final Duration PENDING_SOCKET_HANDOFF_TIMEOUT = Duration.ofMinutes(1); private static final Duration GENERATE_LOCAL_OOB_DATA_TIMEOUT = Duration.ofSeconds(2); @@ -309,7 +282,7 @@ public class AdapterService extends Service { new ArrayList<>(); private BluetoothAdapter mAdapter; - @VisibleForTesting AdapterProperties mAdapterProperties; + private AdapterProperties mAdapterProperties; private AdapterState mAdapterStateMachine; private BondStateMachine mBondStateMachine; private RemoteDevices mRemoteDevices; @@ -341,10 +314,10 @@ public class AdapterService extends Service { private BluetoothSocketManagerBinder mBluetoothSocketManagerBinder; private BluetoothKeystoreService mBluetoothKeystoreService; - private A2dpService mA2dpService; - private A2dpSinkService mA2dpSinkService; private HeadsetService mHeadsetService; private HeadsetClientService mHeadsetClientService; + private A2dpService mA2dpService; + private A2dpSinkService mA2dpSinkService; private BluetoothMapService mMapService; private MapClientService mMapClientService; private HidDeviceService mHidDeviceService; @@ -422,10 +395,6 @@ public class AdapterService extends Service { return sAdapterService; } - AdapterNativeInterface getNative() { - return mNativeInterface; - } - /** Allow test to set an AdapterService to be return by AdapterService.getAdapterService() */ @VisibleForTesting public static synchronized void setAdapterService(AdapterService instance) { @@ -791,10 +760,76 @@ public class AdapterService extends Service { return mActiveDeviceManager; } + public RemoteDevices getRemoteDevices() { + return mRemoteDevices; + } + public SilenceDeviceManager getSilenceDeviceManager() { return mSilenceDeviceManager; } + AdapterNativeInterface getNative() { + return mNativeInterface; + } + + AdapterServiceHandler getHandler() { + return mHandler; + } + + DatabaseManager getDatabaseManager() { + return mDatabaseManager; + } + + AdapterProperties getAdapterProperties() { + return mAdapterProperties; + } + + Map<BluetoothDevice, RemoteCallbackList<IBluetoothMetadataListener>> getMetadataListeners() { + return mMetadataListeners; + } + + Map<String, CallerInfo> getBondAttemptCallerInfo() { + return mBondAttemptCallerInfo; + } + + Optional<PhonePolicy> getPhonePolicy() { + return mPhonePolicy; + } + + BondStateMachine getBondStateMachine() { + return mBondStateMachine; + } + + CompanionDeviceManager getCompanionDeviceManager() { + return mCompanionDeviceManager; + } + + BluetoothSocketManagerBinder getBluetoothSocketManagerBinder() { + return mBluetoothSocketManagerBinder; + } + + RemoteCallbackList<IBluetoothConnectionCallback> getBluetoothConnectionCallbacks() { + return mBluetoothConnectionCallbacks; + } + + RemoteCallbackList<IBluetoothPreferredAudioProfilesCallback> + getPreferredAudioProfilesCallbacks() { + return mPreferredAudioProfilesCallbacks; + } + + RemoteCallbackList<IBluetoothQualityReportReadyCallback> + getBluetoothQualityReportReadyCallbacks() { + return mBluetoothQualityReportReadyCallbacks; + } + + BluetoothHciVendorSpecificDispatcher getBluetoothHciVendorSpecificDispatcher() { + return mBluetoothHciVendorSpecificDispatcher; + } + + BluetoothHciVendorSpecificNativeInterface getBluetoothHciVendorSpecificNativeInterface() { + return mBluetoothHciVendorSpecificNativeInterface; + } + /** * Log L2CAP CoC Server Connection Metrics * @@ -1727,14 +1762,6 @@ public class AdapterService extends Service { * @return false if one of profile is enabled or disabled, true otherwise */ boolean isAllProfilesUnknown(BluetoothDevice device) { - if (mA2dpService != null - && mA2dpService.getConnectionPolicy(device) != CONNECTION_POLICY_UNKNOWN) { - return false; - } - if (mA2dpSinkService != null - && mA2dpSinkService.getConnectionPolicy(device) != CONNECTION_POLICY_UNKNOWN) { - return false; - } if (mHeadsetService != null && mHeadsetService.getConnectionPolicy(device) != CONNECTION_POLICY_UNKNOWN) { return false; @@ -1743,6 +1770,14 @@ public class AdapterService extends Service { && mHeadsetClientService.getConnectionPolicy(device) != CONNECTION_POLICY_UNKNOWN) { return false; } + if (mA2dpService != null + && mA2dpService.getConnectionPolicy(device) != CONNECTION_POLICY_UNKNOWN) { + return false; + } + if (mA2dpSinkService != null + && mA2dpSinkService.getConnectionPolicy(device) != CONNECTION_POLICY_UNKNOWN) { + return false; + } if (mMapClientService != null && mMapClientService.getConnectionPolicy(device) != CONNECTION_POLICY_UNKNOWN) { return false; @@ -1802,18 +1837,7 @@ public class AdapterService extends Service { Log.i(TAG, "connectEnabledProfiles: Connecting Coordinated Set Profile"); mCsipSetCoordinatorService.connect(device); } - if (mA2dpService != null - && isProfileSupported(device, BluetoothProfile.A2DP) - && mA2dpService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN) { - Log.i(TAG, "connectEnabledProfiles: Connecting A2dp"); - mA2dpService.connect(device); - } - if (mA2dpSinkService != null - && isProfileSupported(device, BluetoothProfile.A2DP_SINK) - && mA2dpSinkService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN) { - Log.i(TAG, "connectEnabledProfiles: Connecting A2dp Sink"); - mA2dpSinkService.connect(device); - } + // Order matters, some devices do not accept A2DP connection before HFP connection if (mHeadsetService != null && isProfileSupported(device, BluetoothProfile.HEADSET) && mHeadsetService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN) { @@ -1827,6 +1851,18 @@ public class AdapterService extends Service { Log.i(TAG, "connectEnabledProfiles: Connecting HFP"); mHeadsetClientService.connect(device); } + if (mA2dpService != null + && isProfileSupported(device, BluetoothProfile.A2DP) + && mA2dpService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN) { + Log.i(TAG, "connectEnabledProfiles: Connecting A2dp"); + mA2dpService.connect(device); + } + if (mA2dpSinkService != null + && isProfileSupported(device, BluetoothProfile.A2DP_SINK) + && mA2dpSinkService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN) { + Log.i(TAG, "connectEnabledProfiles: Connecting A2dp Sink"); + mA2dpSinkService.connect(device); + } if (mMapClientService != null && isProfileSupported(device, BluetoothProfile.MAP_CLIENT) && mMapClientService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN) { @@ -1909,10 +1945,10 @@ public class AdapterService extends Service { /** Initializes all the profile services fields */ private void initProfileServices() { Log.i(TAG, "initProfileServices: Initializing all bluetooth profile services"); - mA2dpService = A2dpService.getA2dpService(); - mA2dpSinkService = A2dpSinkService.getA2dpSinkService(); mHeadsetService = HeadsetService.getHeadsetService(); mHeadsetClientService = HeadsetClientService.getHeadsetClientService(); + mA2dpService = A2dpService.getA2dpService(); + mA2dpSinkService = A2dpSinkService.getA2dpSinkService(); mMapService = BluetoothMapService.getBluetoothMapService(); mMapClientService = MapClientService.getMapClientService(); mHidDeviceService = HidDeviceService.getHidDeviceService(); @@ -1932,7 +1968,7 @@ public class AdapterService extends Service { @BluetoothAdapter.RfcommListenerResult @RequiresPermission(BLUETOOTH_CONNECT) - private int startRfcommListener( + int startRfcommListener( String name, ParcelUuid uuid, PendingIntent pendingIntent, AttributionSource source) { if (mBluetoothServerSockets.containsKey(uuid.getUuid())) { Log.d(TAG, "Cannot start RFCOMM listener: UUID " + uuid.getUuid() + "already in use."); @@ -1949,7 +1985,6 @@ public class AdapterService extends Service { } @BluetoothAdapter.RfcommListenerResult - @VisibleForTesting int stopRfcommListener(ParcelUuid uuid, AttributionSource source) { RfcommListenerData listenerData = mBluetoothServerSockets.get(uuid.getUuid()); @@ -1968,7 +2003,6 @@ public class AdapterService extends Service { return listenerData.closeServerAndPendingSockets(mHandler); } - @VisibleForTesting IncomingRfcommSocketInfo retrievePendingSocketForServiceRecord( ParcelUuid uuid, AttributionSource source) { IncomingRfcommSocketInfo socketInfo = new IncomingRfcommSocketInfo(); @@ -2124,7 +2158,6 @@ public class AdapterService extends Service { } } - @VisibleForTesting boolean isAvailable() { return !mCleaningUp; } @@ -2160,2223 +2193,6 @@ public class AdapterService extends Service { } /** - * There is no leak of this binder since it is never re-used and the process is systematically - * killed - */ - @VisibleForTesting - public static class AdapterServiceBinder extends IBluetooth.Stub { - private final AdapterService mService; - - AdapterServiceBinder(AdapterService svc) { - mService = svc; - } - - public AdapterService getService() { - if (!mService.isAvailable()) { - return null; - } - return mService; - } - - @Override - public int getState() { - AdapterService service = getService(); - if (service == null) { - return BluetoothAdapter.STATE_OFF; - } - - return service.getState(); - } - - @Override - public void killBluetoothProcess() { - mService.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); - - Runnable killAction = - () -> { - if (Flags.killInsteadOfExit()) { - Log.i(TAG, "killBluetoothProcess: Calling killProcess(myPid())"); - Process.killProcess(Process.myPid()); - } else { - Log.i(TAG, "killBluetoothProcess: Calling System.exit"); - System.exit(0); - } - }; - - // Post on the main handler to let the cleanup complete before calling exit - mService.mHandler.post(killAction); - - try { - // Wait for Bluetooth to be killed from its main thread - Thread.sleep(1_000); // SystemServer is waiting 2000 ms, we need to wait less here - } catch (InterruptedException e) { - Log.e(TAG, "killBluetoothProcess: Interrupted while waiting for kill"); - } - - // Bluetooth cannot be killed on the main thread; it is in a deadLock. - // Trying to recover by killing the Bluetooth from the binder thread. - // This is bad :( - Counter.logIncrement("bluetooth.value_kill_from_binder_thread"); - Log.wtf(TAG, "Failed to kill Bluetooth using its main thread. Trying from binder"); - killAction.run(); - } - - @Override - public void offToBleOn(boolean quietMode, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "offToBleOn")) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.offToBleOn(quietMode); - } - - @Override - public void onToBleOn(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "onToBleOn")) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.onToBleOn(); - } - - @Override - public String getAddress(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getAddress") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getAddress")) { - return null; - } - - service.enforceCallingOrSelfPermission(LOCAL_MAC_ADDRESS, null); - - return Utils.getAddressStringFromByte(service.mAdapterProperties.getAddress()); - } - - @Override - public List<ParcelUuid> getUuids(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getUuids") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getUuids")) { - return Collections.emptyList(); - } - - ParcelUuid[] parcels = service.mAdapterProperties.getUuids(); - if (parcels == null) { - parcels = new ParcelUuid[0]; - } - return Arrays.asList(parcels); - } - - @Override - public String getIdentityAddress(String address) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getIdentityAddress") - || !Utils.checkConnectPermissionForDataDelivery( - service, - Utils.getCallingAttributionSource(mService), - "AdapterService getIdentityAddress")) { - return null; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getIdentityAddress(address); - } - - @Override - @NonNull - public BluetoothAddress getIdentityAddressWithType(@NonNull String address) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "getIdentityAddressWithType") - || !Utils.checkConnectPermissionForDataDelivery( - service, - Utils.getCallingAttributionSource(mService), - "AdapterService getIdentityAddressWithType")) { - return new BluetoothAddress(null, BluetoothDevice.ADDRESS_TYPE_UNKNOWN); - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getIdentityAddressWithType(address); - } - - @Override - public String getName(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getName") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getName")) { - return null; - } - - return service.getName(); - } - - @Override - public int getNameLengthForAdvertise(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "getNameLengthForAdvertise") - || !Utils.checkAdvertisePermissionForDataDelivery(service, source, TAG)) { - return -1; - } - - return service.getNameLengthForAdvertise(); - } - - @Override - public boolean setName(String name, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setName") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService setName")) { - return false; - } - - if (Flags.emptyNamesAreInvalid()) { - requireNonNull(name); - name = name.trim(); - if (name.isEmpty()) { - throw new IllegalArgumentException("Empty names are not valid"); - } - } - - Log.d(TAG, "AdapterServiceBinder.setName(" + name + ")"); - return service.mAdapterProperties.setName(name); - } - - @Override - public int getScanMode(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getScanMode") - || !Utils.checkScanPermissionForDataDelivery( - service, source, "AdapterService getScanMode")) { - return SCAN_MODE_NONE; - } - - return service.getScanMode(); - } - - @Override - public int setScanMode(int mode, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setScanMode") - || !Utils.checkScanPermissionForDataDelivery( - service, source, "AdapterService setScanMode")) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - String logCaller = Utils.getUidPidString() + " packageName=" + source.getPackageName(); - CompletableFuture<Boolean> future = new CompletableFuture<>(); - mService.mHandler.post( - () -> - future.complete( - service.getState() == BluetoothAdapter.STATE_ON - && service.setScanMode(mode, logCaller))); - return future.join() - ? BluetoothStatusCodes.SUCCESS - : BluetoothStatusCodes.ERROR_UNKNOWN; - } - - @Override - public long getDiscoverableTimeout(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getDiscoverableTimeout") - || !Utils.checkScanPermissionForDataDelivery( - service, source, "AdapterService getDiscoverableTimeout")) { - return -1; - } - - return service.mAdapterProperties.getDiscoverableTimeout(); - } - - @Override - public int setDiscoverableTimeout(long timeout, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setDiscoverableTimeout") - || !Utils.checkScanPermissionForDataDelivery( - service, source, "AdapterService setDiscoverableTimeout")) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.mAdapterProperties.setDiscoverableTimeout((int) timeout) - ? BluetoothStatusCodes.SUCCESS - : BluetoothStatusCodes.ERROR_UNKNOWN; - } - - @Override - public boolean startDiscovery(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "startDiscovery")) { - return false; - } - - if (!Utils.checkScanPermissionForDataDelivery(service, source, "Starting discovery.")) { - return false; - } - - Log.i(TAG, "startDiscovery: from " + Utils.getUidPidString()); - return service.startDiscovery(source); - } - - @Override - public boolean cancelDiscovery(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "cancelDiscovery") - || !Utils.checkScanPermissionForDataDelivery( - service, source, "AdapterService cancelDiscovery")) { - return false; - } - - Log.i(TAG, "cancelDiscovery: from " + Utils.getUidPidString()); - return service.mNativeInterface.cancelDiscovery(); - } - - @Override - public boolean isDiscovering(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "isDiscovering") - || !Utils.checkScanPermissionForDataDelivery( - service, source, "AdapterService isDiscovering")) { - return false; - } - - return service.mAdapterProperties.isDiscovering(); - } - - @Override - public long getDiscoveryEndMillis(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getDiscoveryEndMillis") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return -1; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.mAdapterProperties.discoveryEndMillis(); - } - - @Override - public List<BluetoothDevice> getMostRecentlyConnectedDevices(AttributionSource source) { - // don't check caller, may be called from system UI - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getMostRecentlyConnectedDevices")) { - return Collections.emptyList(); - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.mDatabaseManager.getMostRecentlyConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getBondedDevices(AttributionSource source) { - // don't check caller, may be called from system UI - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getBondedDevices")) { - return Collections.emptyList(); - } - - return Arrays.asList(service.getBondedDevices()); - } - - @Override - public int getAdapterConnectionState() { - // don't check caller, may be called from system UI - AdapterService service = getService(); - if (service == null) { - return BluetoothAdapter.STATE_DISCONNECTED; - } - - return service.mAdapterProperties.getConnectionState(); - } - - /** - * This method has an associated binder cache. The invalidation methods must be changed if - * the logic behind this method changes. - */ - @Override - public int getProfileConnectionState(int profile, AttributionSource source) { - AdapterService service = getService(); - boolean checkConnect = false; - final int callingUid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - checkConnect = CompatChanges.isChangeEnabled(ENFORCE_CONNECT, callingUid); - } finally { - Binder.restoreCallingIdentity(token); - } - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "getProfileConnectionState") - || (checkConnect - && !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getProfileConnectionState"))) { - return STATE_DISCONNECTED; - } - - return service.mAdapterProperties.getProfileConnectionState(profile); - } - - @Override - public boolean createBond( - BluetoothDevice device, - int transport, - AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "createBond") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService createBond")) { - return false; - } - - Log.i( - TAG, - "createBond:" - + (" device=" + device) - + (" transport=" + transport) - + (" from " + Utils.getUidPidString())); - return service.createBond( - device, transport, null, null, source.getPackageName()); - } - - @Override - public boolean createBondOutOfBand( - BluetoothDevice device, - int transport, - OobData remoteP192Data, - OobData remoteP256Data, - AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "createBond") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService createBond")) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - Log.i( - TAG, - "createBondOutOfBand:" - + (" device=" + device) - + (" transport=" + transport) - + (" from " + Utils.getUidPidString())); - return service.createBond( - device, transport, remoteP192Data, remoteP256Data, source.getPackageName()); - } - - @Override - public boolean cancelBondProcess(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "cancelBondProcess") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService cancelBondProcess")) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - Log.i(TAG, "cancelBondProcess: device=" + device + ", from " + Utils.getUidPidString()); - - DeviceProperties deviceProp = service.mRemoteDevices.getDeviceProperties(device); - if (deviceProp != null) { - deviceProp.setBondingInitiatedLocally(false); - } - - service.logUserBondResponse(device, false, source); - return service.mNativeInterface.cancelBond(getBytesFromAddress(device.getAddress())); - } - - @Override - public boolean removeBond(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "removeBond") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService removeBond")) { - return false; - } - - Log.i(TAG, "removeBond: device=" + device + ", from " + Utils.getUidPidString()); - - DeviceProperties deviceProp = service.mRemoteDevices.getDeviceProperties(device); - if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) { - Log.w( - TAG, - device - + " cannot be removed since " - + ((deviceProp == null) - ? "properties are empty" - : "bond state is " + deviceProp.getBondState())); - return false; - } - service.logUserBondResponse(device, false, source); - service.mBondAttemptCallerInfo.remove(device.getAddress()); - service.mPhonePolicy.ifPresent(policy -> policy.onRemoveBondRequest(device)); - deviceProp.setBondingInitiatedLocally(false); - - Message msg = service.mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND); - msg.obj = device; - service.mBondStateMachine.sendMessage(msg); - return true; - } - - @Override - public int getBondState(BluetoothDevice device, AttributionSource source) { - // don't check caller, may be called from system UI - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getBondState")) { - return BluetoothDevice.BOND_NONE; - } - - return service.getBondState(device); - } - - @Override - public boolean isBondingInitiatedLocally(BluetoothDevice device, AttributionSource source) { - // don't check caller, may be called from system UI - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService isBondingInitiatedLocally")) { - return false; - } - - DeviceProperties deviceProp = service.mRemoteDevices.getDeviceProperties(device); - return deviceProp != null && deviceProp.isBondingInitiatedLocally(); - } - - @Override - public void generateLocalOobData( - int transport, IBluetoothOobDataCallback callback, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "generateLocalOobData") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.generateLocalOobData(transport, callback); - } - - @Override - public long getSupportedProfiles(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return 0; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return Config.getSupportedProfilesBitMask(); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getConnectionState")) { - return BluetoothDevice.CONNECTION_STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } - - @Override - public int getConnectionHandle( - BluetoothDevice device, int transport, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getConnectionHandle") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothDevice.ERROR; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectionHandle(device, transport); - } - - @Override - public boolean canBondWithoutDialog(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.canBondWithoutDialog(device); - } - - @Override - public String getPackageNameOfBondingApplication( - BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - - if (service == null - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getPackageNameOfBondingApplication(device); - } - - @Override - public boolean removeActiveDevice(@ActiveDeviceUse int profiles, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "removeActiveDevice") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - Log.i( - TAG, - "removeActiveDevice: profiles=" - + profiles - + ", from " - + Utils.getUidPidString()); - return service.setActiveDevice(null, profiles); - } - - @Override - public boolean setActiveDevice( - BluetoothDevice device, @ActiveDeviceUse int profiles, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setActiveDevice") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - Log.i( - TAG, - "setActiveDevice: device=" - + device - + ", profiles=" - + profiles - + ", from " - + Utils.getUidPidString()); - - return service.setActiveDevice(device, profiles); - } - - @Override - public List<BluetoothDevice> getActiveDevices( - @ActiveDeviceProfile int profile, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getActiveDevices") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return Collections.emptyList(); - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getActiveDevices(profile); - } - - @Override - public int connectAllEnabledProfiles(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null || !service.isEnabled()) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "connectAllEnabledProfiles")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - if (device == null) { - throw new IllegalArgumentException("device cannot be null"); - } - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - - service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - Log.i( - TAG, - "connectAllEnabledProfiles: device=" - + device - + ", from " - + Utils.getUidPidString()); - MetricsLogger.getInstance() - .logBluetoothEvent( - device, - BluetoothStatsLog - .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__INITIATOR_CONNECTION, - BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__START, - source.getUid()); - - try { - return service.connectAllEnabledProfiles(device); - } catch (Exception e) { - Log.v(TAG, "connectAllEnabledProfiles() failed", e); - SneakyThrow.sneakyThrow(e); - throw new RuntimeException(e); - } - } - - @Override - public int disconnectAllEnabledProfiles(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "disconnectAllEnabledProfiles")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - if (device == null) { - throw new IllegalArgumentException("device cannot be null"); - } - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - Log.i( - TAG, - "disconnectAllEnabledProfiles: device=" - + device - + ", from " - + Utils.getUidPidString()); - - try { - return service.disconnectAllEnabledProfiles(device); - } catch (Exception e) { - Log.v(TAG, "disconnectAllEnabledProfiles() failed", e); - SneakyThrow.sneakyThrow(e); - throw new RuntimeException(e); - } - } - - @Override - public String getRemoteName(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getRemoteName") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getRemoteName")) { - return null; - } - - return service.getRemoteName(device); - } - - @Override - public int getRemoteType(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getRemoteType") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getRemoteType")) { - return BluetoothDevice.DEVICE_TYPE_UNKNOWN; - } - - return service.getRemoteType(device); - } - - @Override - public String getRemoteAlias(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getRemoteAlias") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getRemoteAlias")) { - return null; - } - - DeviceProperties deviceProp = service.mRemoteDevices.getDeviceProperties(device); - return deviceProp != null ? deviceProp.getAlias() : null; - } - - @Override - public int setRemoteAlias(BluetoothDevice device, String name, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "setRemoteAlias")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - if (name != null && name.isEmpty()) { - throw new IllegalArgumentException("alias cannot be the empty string"); - } - - if (!Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService setRemoteAlias")) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - - Utils.enforceCdmAssociationIfNotBluetoothPrivileged( - service, service.mCompanionDeviceManager, source, device); - - DeviceProperties deviceProp = service.mRemoteDevices.getDeviceProperties(device); - if (deviceProp == null) { - return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED; - } - deviceProp.setAlias(device, name); - return BluetoothStatusCodes.SUCCESS; - } - - @Override - public int getRemoteClass(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getRemoteClass") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getRemoteClass")) { - return 0; - } - - return service.getRemoteClass(device); - } - - @Override - public List<ParcelUuid> getRemoteUuids(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getRemoteUuids") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getRemoteUuids")) { - return Collections.emptyList(); - } - - final ParcelUuid[] parcels = service.getRemoteUuids(device); - if (parcels == null) { - return null; - } - return Arrays.asList(parcels); - } - - @Override - public boolean fetchRemoteUuids( - BluetoothDevice device, int transport, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "fetchRemoteUuids") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService fetchRemoteUuids")) { - return false; - } - if (transport != TRANSPORT_AUTO) { - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - } - - Log.i( - TAG, - "fetchRemoteUuids: device=" - + device - + ", transport=" - + transport - + ", from " - + Utils.getUidPidString()); - - service.mRemoteDevices.fetchUuids(device, transport); - MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.SDP_FETCH_UUID_REQUEST, 1); - return true; - } - - @Override - public boolean setPin( - BluetoothDevice device, - boolean accept, - int len, - byte[] pinCode, - AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setPin") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService setPin")) { - return false; - } - - DeviceProperties deviceProp = service.mRemoteDevices.getDeviceProperties(device); - // Only allow setting a pin in bonding state, or bonded state in case of security - // upgrade. - if (deviceProp == null || !deviceProp.isBondingOrBonded()) { - Log.e(TAG, "setPin: device=" + device + ", not bonding"); - return false; - } - if (pinCode.length != len) { - android.util.EventLog.writeEvent( - 0x534e4554, "139287605", -1, "PIN code length mismatch"); - return false; - } - service.logUserBondResponse(device, accept, source); - Log.i( - TAG, - "setPin: device=" - + device - + ", accept=" - + accept - + ", from " - + Utils.getUidPidString()); - return service.mNativeInterface.pinReply( - getBytesFromAddress(device.getAddress()), accept, len, pinCode); - } - - @Override - public boolean setPasskey( - BluetoothDevice device, - boolean accept, - int len, - byte[] passkey, - AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setPasskey") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService setPasskey")) { - return false; - } - - DeviceProperties deviceProp = service.mRemoteDevices.getDeviceProperties(device); - if (deviceProp == null || !deviceProp.isBonding()) { - Log.e(TAG, "setPasskey: device=" + device + ", not bonding"); - return false; - } - if (passkey.length != len) { - android.util.EventLog.writeEvent( - 0x534e4554, "139287605", -1, "Passkey length mismatch"); - return false; - } - service.logUserBondResponse(device, accept, source); - Log.i( - TAG, - "setPasskey: device=" - + device - + ", accept=" - + accept - + ", from " - + Utils.getUidPidString()); - - return service.mNativeInterface.sspReply( - getBytesFromAddress(device.getAddress()), - AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, - accept, - Utils.byteArrayToInt(passkey)); - } - - @Override - public boolean setPairingConfirmation( - BluetoothDevice device, boolean accept, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setPairingConfirmation") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - DeviceProperties deviceProp = service.mRemoteDevices.getDeviceProperties(device); - if (deviceProp == null || !deviceProp.isBonding()) { - Log.e(TAG, "setPairingConfirmation: device=" + device + ", not bonding"); - return false; - } - service.logUserBondResponse(device, accept, source); - Log.i( - TAG, - "setPairingConfirmation: device=" - + device - + ", accept=" - + accept - + ", from " - + Utils.getUidPidString()); - - return service.mNativeInterface.sspReply( - getBytesFromAddress(device.getAddress()), - AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION, - accept, - 0); - } - - @Override - public boolean getSilenceMode(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getSilenceMode") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.mSilenceDeviceManager.getSilenceMode(device); - } - - @Override - public boolean setSilenceMode( - BluetoothDevice device, boolean silence, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setSilenceMode") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.mSilenceDeviceManager.setSilenceMode(device, silence); - return true; - } - - @Override - public int getPhonebookAccessPermission(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "getPhonebookAccessPermission") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getPhonebookAccessPermission")) { - return BluetoothDevice.ACCESS_UNKNOWN; - } - - return service.getPhonebookAccessPermission(device); - } - - @Override - public boolean setPhonebookAccessPermission( - BluetoothDevice device, int value, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "setPhonebookAccessPermission") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.setPhonebookAccessPermission(device, value); - return true; - } - - @Override - public int getMessageAccessPermission(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "getMessageAccessPermission") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getMessageAccessPermission")) { - return BluetoothDevice.ACCESS_UNKNOWN; - } - - return service.getMessageAccessPermission(device); - } - - @Override - public boolean setMessageAccessPermission( - BluetoothDevice device, int value, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "setMessageAccessPermission") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.setMessageAccessPermission(device, value); - return true; - } - - @Override - public int getSimAccessPermission(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getSimAccessPermission") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getSimAccessPermission")) { - return BluetoothDevice.ACCESS_UNKNOWN; - } - - return service.getSimAccessPermission(device); - } - - @Override - public boolean setSimAccessPermission( - BluetoothDevice device, int value, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setSimAccessPermission") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.setSimAccessPermission(device, value); - return true; - } - - @Override - public void logL2capcocServerConnection( - BluetoothDevice device, - int port, - boolean isSecured, - int result, - long socketCreationTimeMillis, - long socketCreationLatencyMillis, - long socketConnectionTimeMillis, - long timeoutMillis) { - AdapterService service = getService(); - if (service == null) { - return; - } - service.logL2capcocServerConnection( - device, - port, - isSecured, - result, - socketCreationTimeMillis, - socketCreationLatencyMillis, - socketConnectionTimeMillis, - timeoutMillis, - Binder.getCallingUid()); - } - - @Override - public IBluetoothSocketManager getSocketManager() { - AdapterService service = getService(); - if (service == null) { - return null; - } - - return IBluetoothSocketManager.Stub.asInterface(service.mBluetoothSocketManagerBinder); - } - - @Override - public void logL2capcocClientConnection( - BluetoothDevice device, - int port, - boolean isSecured, - int result, - long socketCreationTimeNanos, - long socketCreationLatencyNanos, - long socketConnectionTimeNanos) { - AdapterService service = getService(); - if (service == null) { - return; - } - service.logL2capcocClientConnection( - device, - port, - isSecured, - result, - socketCreationTimeNanos, - socketCreationLatencyNanos, - socketConnectionTimeNanos, - Binder.getCallingUid()); - } - - @Override - public void logRfcommConnectionAttempt( - BluetoothDevice device, - boolean isSecured, - int resultCode, - long socketCreationTimeNanos, - boolean isSerialPort) { - AdapterService service = getService(); - if (service == null) { - return; - } - service.logRfcommConnectionAttempt( - device, - isSecured, - resultCode, - socketCreationTimeNanos, - isSerialPort, - Binder.getCallingUid()); - } - - @Override - public boolean sdpSearch( - BluetoothDevice device, ParcelUuid uuid, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "sdpSearch") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService sdpSearch")) { - return false; - } - return service.sdpSearch(device, uuid); - } - - @Override - public int getBatteryLevel(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getBatteryLevel") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getBatteryLevel")) { - return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; - } - - DeviceProperties deviceProp = service.mRemoteDevices.getDeviceProperties(device); - if (deviceProp == null) { - return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; - } - return deviceProp.getBatteryLevel(); - } - - @Override - public int getMaxConnectedAudioDevices(AttributionSource source) { - // don't check caller, may be called from system UI - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getMaxConnectedAudioDevices")) { - return -1; - } - - return service.getMaxConnectedAudioDevices(); - } - - @Override - public boolean factoryReset(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.factoryReset(); - } - - @Override - public void registerBluetoothConnectionCallback( - IBluetoothConnectionCallback callback, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "registerBluetoothConnectionCallback") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.mBluetoothConnectionCallbacks.register(callback); - } - - @Override - public void unregisterBluetoothConnectionCallback( - IBluetoothConnectionCallback callback, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "unregisterBluetoothConnectionCallback") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.mBluetoothConnectionCallbacks.unregister(callback); - } - - @Override - public void registerCallback(IBluetoothCallback callback, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "registerCallback") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.registerRemoteCallback(callback); - } - - @Override - public void unregisterCallback(IBluetoothCallback callback, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "unregisterCallback") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.unregisterRemoteCallback(callback); - } - - @Override - public boolean isMultiAdvertisementSupported() { - AdapterService service = getService(); - if (service == null) { - return false; - } - - int val = service.mAdapterProperties.getNumOfAdvertisementInstancesSupported(); - return val >= MIN_ADVT_INSTANCES_FOR_MA; - } - - /** - * This method has an associated binder cache. The invalidation methods must be changed if - * the logic behind this method changes. - */ - @Override - public boolean isOffloadedFilteringSupported() { - AdapterService service = getService(); - if (service == null) { - return false; - } - - int val = service.getNumOfOffloadedScanFilterSupported(); - return val >= MIN_OFFLOADED_FILTERS; - } - - @Override - public boolean isOffloadedScanBatchingSupported() { - AdapterService service = getService(); - if (service == null) { - return false; - } - - int val = service.getOffloadedScanResultStorage(); - return val >= MIN_OFFLOADED_SCAN_STORAGE_BYTES; - } - - @Override - public boolean isLe2MPhySupported() { - AdapterService service = getService(); - if (service == null) { - return false; - } - - return service.isLe2MPhySupported(); - } - - @Override - public boolean isLeCodedPhySupported() { - AdapterService service = getService(); - if (service == null) { - return false; - } - - return service.isLeCodedPhySupported(); - } - - @Override - public boolean isLeExtendedAdvertisingSupported() { - AdapterService service = getService(); - if (service == null) { - return false; - } - - return service.isLeExtendedAdvertisingSupported(); - } - - @Override - public boolean isLePeriodicAdvertisingSupported() { - AdapterService service = getService(); - if (service == null) { - return false; - } - - return service.isLePeriodicAdvertisingSupported(); - } - - @Override - public int isLeAudioSupported() { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - - Set<Integer> supportedProfileServices = - Arrays.stream(Config.getSupportedProfiles()) - .boxed() - .collect(Collectors.toSet()); - int[] leAudioUnicastProfiles = Config.getLeAudioUnicastProfiles(); - - if (Arrays.stream(leAudioUnicastProfiles) - .allMatch(supportedProfileServices::contains)) { - return BluetoothStatusCodes.FEATURE_SUPPORTED; - } - - return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; - } - - @Override - public int isLeAudioBroadcastSourceSupported() { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - - long supportBitMask = Config.getSupportedProfilesBitMask(); - if ((supportBitMask & (1 << BluetoothProfile.LE_AUDIO_BROADCAST)) != 0) { - return BluetoothStatusCodes.FEATURE_SUPPORTED; - } - - return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; - } - - @Override - public int isLeAudioBroadcastAssistantSupported() { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - - int[] supportedProfileServices = Config.getSupportedProfiles(); - - if (Arrays.stream(supportedProfileServices) - .anyMatch( - profileId -> - profileId == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)) { - return BluetoothStatusCodes.FEATURE_SUPPORTED; - } - - return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; - } - - @Override - public int isDistanceMeasurementSupported(AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } else if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "isDistanceMeasurementSupported")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } else if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return BluetoothStatusCodes.FEATURE_SUPPORTED; - } - - @Override - public int getLeMaximumAdvertisingDataLength() { - AdapterService service = getService(); - if (service == null) { - return 0; - } - - return service.getLeMaximumAdvertisingDataLength(); - } - - @Override - public boolean isActivityAndEnergyReportingSupported() { - AdapterService service = getService(); - if (service == null) { - return false; - } - - return service.mAdapterProperties.isActivityAndEnergyReportingSupported(); - } - - @Override - public BluetoothActivityEnergyInfo reportActivityInfo(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.reportActivityInfo(); - } - - @Override - public boolean registerMetadataListener( - IBluetoothMetadataListener listener, - BluetoothDevice device, - AttributionSource source) { - requireNonNull(device); - requireNonNull(listener); - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "registerMetadataListener") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.mHandler.post( - () -> - service.mMetadataListeners - .computeIfAbsent(device, k -> new RemoteCallbackList()) - .register(listener)); - - return true; - } - - @Override - public boolean unregisterMetadataListener( - IBluetoothMetadataListener listener, - BluetoothDevice device, - AttributionSource source) { - requireNonNull(device); - requireNonNull(listener); - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "unregisterMetadataListener") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.mHandler.post( - () -> - service.mMetadataListeners.computeIfPresent( - device, - (k, v) -> { - v.unregister(listener); - if (v.getRegisteredCallbackCount() == 0) { - return null; - } - return v; - })); - return true; - } - - @Override - public boolean setMetadata( - BluetoothDevice device, int key, byte[] value, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setMetadata") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.setMetadata(device, key, value); - } - - @Override - public byte[] getMetadata(BluetoothDevice device, int key, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getMetadata") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getMetadata(device, key); - } - - @Override - public int isRequestAudioPolicyAsSinkSupported( - BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "isRequestAudioPolicyAsSinkSupported") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.FEATURE_NOT_CONFIGURED; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.isRequestAudioPolicyAsSinkSupported(device); - } - - @Override - public int requestAudioPolicyAsSink( - BluetoothDevice device, - BluetoothSinkAudioPolicy policies, - AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } else if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "requestAudioPolicyAsSink")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } else if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.requestAudioPolicyAsSink(device, policies); - } - - @Override - public BluetoothSinkAudioPolicy getRequestedAudioPolicyAsSink( - BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "getRequestedAudioPolicyAsSink") - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getRequestedAudioPolicyAsSink(device); - } - - @Override - public void requestActivityInfo( - IBluetoothActivityEnergyInfoListener listener, AttributionSource source) { - BluetoothActivityEnergyInfo info = reportActivityInfo(source); - try { - listener.onBluetoothActivityEnergyInfoAvailable(info); - } catch (RemoteException e) { - Log.e(TAG, "onBluetoothActivityEnergyInfo: RemoteException", e); - } - } - - @Override - public void bleOnToOn(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "bleOnToOn")) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.bleOnToOn(); - } - - @Override - public void bleOnToOff(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "bleOnToOff")) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.bleOnToOff(); - } - - @Override - public void dump(FileDescriptor fd, String[] args) { - PrintWriter writer = new PrintWriter(new FileOutputStream(fd)); - AdapterService service = getService(); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(DUMP, null); - - service.dump(fd, writer, args); - writer.close(); - } - - @Override - public boolean allowLowLatencyAudio(boolean allowed, BluetoothDevice device) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "allowLowLatencyAudio") - || !Utils.checkConnectPermissionForDataDelivery( - service, - Utils.getCallingAttributionSource(service), - "AdapterService allowLowLatencyAudio")) { - return false; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.allowLowLatencyAudio(allowed, device); - } - - @Override - public int startRfcommListener( - String name, - ParcelUuid uuid, - PendingIntent pendingIntent, - AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "startRfcommListener") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService startRfcommListener")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.startRfcommListener(name, uuid, pendingIntent, source); - } - - @Override - public int stopRfcommListener(ParcelUuid uuid, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser(service, TAG, "stopRfcommListener") - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService stopRfcommListener")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.stopRfcommListener(uuid, source); - } - - @Override - public IncomingRfcommSocketInfo retrievePendingSocketForServiceRecord( - ParcelUuid uuid, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "retrievePendingSocketForServiceRecord") - || !Utils.checkConnectPermissionForDataDelivery( - service, - source, - "AdapterService retrievePendingSocketForServiceRecord")) { - return null; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.retrievePendingSocketForServiceRecord(uuid, source); - } - - @Override - public void setForegroundUserId(int userId, AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery( - service, - Utils.getCallingAttributionSource(mService), - "AdapterService setForegroundUserId")) { - return; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - Utils.setForegroundUserId(userId); - } - - @Override - public int setPreferredAudioProfiles( - BluetoothDevice device, Bundle modeToProfileBundle, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "setPreferredAudioProfiles")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - requireNonNull(device); - requireNonNull(modeToProfileBundle); - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - if (service.getBondState(device) != BluetoothDevice.BOND_BONDED) { - return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED; - } - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.setPreferredAudioProfiles(device, modeToProfileBundle); - } - - @Override - public Bundle getPreferredAudioProfiles(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return Bundle.EMPTY; - } - if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "getPreferredAudioProfiles")) { - return Bundle.EMPTY; - } - requireNonNull(device); - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - if (service.getBondState(device) != BluetoothDevice.BOND_BONDED) { - return Bundle.EMPTY; - } - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return Bundle.EMPTY; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getPreferredAudioProfiles(device); - } - - @Override - public int notifyActiveDeviceChangeApplied( - BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystem(TAG, "notifyActiveDeviceChangeApplied")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - requireNonNull(device); - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - if (service.getBondState(device) != BluetoothDevice.BOND_BONDED) { - return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED; - } - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.notifyActiveDeviceChangeApplied(device); - } - - @Override - public int isDualModeAudioEnabled(AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - if (!Utils.isDualModeAudioEnabled()) { - return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; - } - - return BluetoothStatusCodes.SUCCESS; - } - - @Override - public int registerPreferredAudioProfilesChangedCallback( - IBluetoothPreferredAudioProfilesCallback callback, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "registerPreferredAudioProfilesChangedCallback")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - requireNonNull(callback); - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - // If LE only mode is enabled, the dual mode audio feature is disabled - if (!Utils.isDualModeAudioEnabled()) { - return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; - } - - service.mPreferredAudioProfilesCallbacks.register(callback); - return BluetoothStatusCodes.SUCCESS; - } - - @Override - public int unregisterPreferredAudioProfilesChangedCallback( - IBluetoothPreferredAudioProfilesCallback callback, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "unregisterPreferredAudioProfilesChangedCallback")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - requireNonNull(callback); - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - if (!service.mPreferredAudioProfilesCallbacks.unregister(callback)) { - Log.e( - TAG, - "unregisterPreferredAudioProfilesChangedCallback: callback was never " - + "registered"); - return BluetoothStatusCodes.ERROR_CALLBACK_NOT_REGISTERED; - } - return BluetoothStatusCodes.SUCCESS; - } - - @Override - public int registerBluetoothQualityReportReadyCallback( - IBluetoothQualityReportReadyCallback callback, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "registerBluetoothQualityReportReadyCallback")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - requireNonNull(callback); - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.mBluetoothQualityReportReadyCallbacks.register(callback); - return BluetoothStatusCodes.SUCCESS; - } - - @Override - public int unregisterBluetoothQualityReportReadyCallback( - IBluetoothQualityReportReadyCallback callback, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "unregisterBluetoothQualityReportReadyCallback")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - requireNonNull(callback); - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - if (!service.mBluetoothQualityReportReadyCallbacks.unregister(callback)) { - Log.e( - TAG, - "unregisterBluetoothQualityReportReadyCallback: callback was never " - + "registered"); - return BluetoothStatusCodes.ERROR_CALLBACK_NOT_REGISTERED; - } - return BluetoothStatusCodes.SUCCESS; - } - - @Override - public void registerHciVendorSpecificCallback( - IBluetoothHciVendorSpecificCallback callback, int[] eventCodes) { - AdapterService service = getService(); - if (service == null) { - return; - } - if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "registerHciVendorSpecificCallback")) { - throw new SecurityException("not allowed"); - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - requireNonNull(callback); - requireNonNull(eventCodes); - - Set<Integer> eventCodesSet = - Arrays.stream(eventCodes).boxed().collect(Collectors.toSet()); - if (eventCodesSet.stream() - .anyMatch((n) -> (n < 0) || (n >= 0x52 && n < 0x60) || (n > 0xff))) { - throw new IllegalArgumentException("invalid vendor-specific event code"); - } - - service.mBluetoothHciVendorSpecificDispatcher.register(callback, eventCodesSet); - } - - @Override - public void unregisterHciVendorSpecificCallback( - IBluetoothHciVendorSpecificCallback callback) { - AdapterService service = getService(); - if (service == null) { - return; - } - if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "unregisterHciVendorSpecificCallback")) { - throw new SecurityException("not allowed"); - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - requireNonNull(callback); - - service.mBluetoothHciVendorSpecificDispatcher.unregister(callback); - } - - @Override - public void sendHciVendorSpecificCommand( - int ocf, byte[] parameters, IBluetoothHciVendorSpecificCallback callback) { - AdapterService service = getService(); - if (service == null) { - return; - } - if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "sendHciVendorSpecificCommand")) { - throw new SecurityException("not allowed"); - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - // Open this no-op android command for test purpose - int getVendorCapabilitiesOcf = 0x153; - if (ocf < 0 - || (ocf >= 0x150 && ocf < 0x160 && ocf != getVendorCapabilitiesOcf) - || (ocf > 0x3ff)) { - throw new IllegalArgumentException("invalid vendor-specific event code"); - } - requireNonNull(parameters); - if (parameters.length > 255) { - throw new IllegalArgumentException("Parameters size is too big"); - } - - Optional<byte[]> cookie = - service.mBluetoothHciVendorSpecificDispatcher.getRegisteredCookie(callback); - if (!cookie.isPresent()) { - Log.e(TAG, "send command without registered callback"); - throw new IllegalStateException("callback not registered"); - } - - service.mBluetoothHciVendorSpecificNativeInterface.sendCommand( - ocf, parameters, cookie.get()); - } - - @Override - public int getOffloadedTransportDiscoveryDataScanSupported(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !callerIsSystemOrActiveOrManagedUser( - service, TAG, "getOffloadedTransportDiscoveryDataScanSupported") - || !Utils.checkScanPermissionForDataDelivery( - service, source, "getOffloadedTransportDiscoveryDataScanSupported")) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getOffloadedTransportDiscoveryDataScanSupported(); - } - - @Override - public boolean isMediaProfileConnected(AttributionSource source) { - AdapterService service = getService(); - if (service == null - || !Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService.isMediaProfileConnected")) { - return false; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.isMediaProfileConnected(); - } - - @Override - public IBinder getBluetoothGatt() { - AdapterService service = getService(); - return service == null ? null : service.getBluetoothGatt(); - } - - @Override - public IBinder getBluetoothScan() { - AdapterService service = getService(); - return service == null ? null : service.getBluetoothScan(); - } - - @Override - public void unregAllGattClient(AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.unregAllGattClient(source); - } - - @Override - public IBinder getProfile(int profileId) { - AdapterService service = getService(); - if (service == null) { - return null; - } - - return service.getProfile(profileId); - } - - @Override - public int setActiveAudioDevicePolicy( - BluetoothDevice device, int activeAudioDevicePolicy, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "setActiveAudioDevicePolicy")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.mDatabaseManager.setActiveAudioDevicePolicy( - device, activeAudioDevicePolicy); - } - - @Override - public int getActiveAudioDevicePolicy(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return BluetoothDevice.ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT; - } - if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "getActiveAudioDevicePolicy")) { - throw new IllegalStateException( - "Caller is not the system or part of the active/managed user"); - } - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - if (!Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return BluetoothDevice.ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.mDatabaseManager.getActiveAudioDevicePolicy(device); - } - - @Override - public int setMicrophonePreferredForCalls( - BluetoothDevice device, boolean enabled, AttributionSource source) { - requireNonNull(device); - AdapterService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "setMicrophonePreferredForCalls")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - if (!Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService setMicrophonePreferredForCalls")) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.mDatabaseManager.setMicrophonePreferredForCalls(device, enabled); - } - - @Override - public boolean isMicrophonePreferredForCalls( - BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - AdapterService service = getService(); - if (service == null) { - return true; - } - if (!callerIsSystemOrActiveOrManagedUser( - service, TAG, "isMicrophonePreferredForCalls")) { - throw new IllegalStateException( - "Caller is not the system or part of the active/managed user"); - } - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - if (!Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService isMicrophonePreferredForCalls")) { - return true; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.mDatabaseManager.isMicrophonePreferredForCalls(device); - } - - @Override - public boolean isLeCocSocketOffloadSupported(AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return false; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.isLeCocSocketOffloadSupported(); - } - - @Override - public boolean isRfcommSocketOffloadSupported(AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return false; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.isRfcommSocketOffloadSupported(); - } - - @Override - public IBinder getBluetoothAdvertise() { - AdapterService service = getService(); - return service == null ? null : service.getBluetoothAdvertise(); - } - - @Override - public IBinder getDistanceMeasurement() { - AdapterService service = getService(); - return service == null ? null : service.getDistanceMeasurement(); - } - - @Override - public int getKeyMissingCount(BluetoothDevice device, AttributionSource source) { - AdapterService service = getService(); - if (service == null) { - return -1; - } - if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "getKeyMissingCount")) { - throw new IllegalStateException( - "Caller is not the system or part of the active/managed user"); - } - if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { - throw new IllegalArgumentException("device cannot have an invalid address"); - } - if (!Utils.checkConnectPermissionForDataDelivery( - service, source, "AdapterService getKeyMissingCount")) { - return -1; - } - - return service.mDatabaseManager.getKeyMissingCount(device); - } - } - - /** * Gets the preferred audio profiles for the device. See {@link * BluetoothAdapter#getPreferredAudioProfiles(BluetoothDevice)} for more details. * @@ -4449,7 +2265,7 @@ public class AdapterService extends Service { * @param modeToProfileBundle is the preferences we want to set for the device * @return whether the preferences were successfully requested */ - private int setPreferredAudioProfiles(BluetoothDevice device, Bundle modeToProfileBundle) { + int setPreferredAudioProfiles(BluetoothDevice device, Bundle modeToProfileBundle) { Log.i(TAG, "setPreferredAudioProfiles for device=" + device); if (!isDualModeAudioEnabled()) { Log.e(TAG, "setPreferredAudioProfiles called while sysprop is disabled"); @@ -4669,7 +2485,7 @@ public class AdapterService extends Service { * @param device the remote device whose preferred audio profiles have been changed * @return whether the Bluetooth stack acknowledged the change successfully */ - private int notifyActiveDeviceChangeApplied(BluetoothDevice device) { + int notifyActiveDeviceChangeApplied(BluetoothDevice device) { if (mLeAudioService == null) { Log.e(TAG, "LE Audio profile not enabled"); return BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED; @@ -4873,12 +2689,8 @@ public class AdapterService extends Service { return Utils.getBytesFromAddress(deviceProp.getIdentityAddress()); } - if (Flags.identityAddressNullIfNotKnown()) { - // Return null if identity address unknown - return null; - } else { - return Utils.getByteAddress(device); - } + // Return null if identity address unknown + return null; } public BluetoothDevice getDeviceFromByte(byte[] address) { @@ -4896,14 +2708,9 @@ public class AdapterService extends Service { DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); if (deviceProp != null && deviceProp.getIdentityAddress() != null) { return deviceProp.getIdentityAddress(); - } else { - if (Flags.identityAddressNullIfNotKnown()) { - // Return null if identity address unknown - return null; - } else { - return address; - } } + // Return null if identity address unknown + return null; } /** @@ -4929,16 +2736,21 @@ public class AdapterService extends Service { } identityAddressType = deviceProp.getIdentityAddressType(); } else { - if (Flags.identityAddressNullIfNotKnown()) { - identityAddress = null; - } else { - identityAddress = address; - } + identityAddress = null; } return new BluetoothAddress(identityAddress, identityAddressType); } + public boolean addAssociatedPackage(BluetoothDevice device, String packageName) { + DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); + if (deviceProp == null) { + return false; + } + deviceProp.addPackage(packageName); + return true; + } + private record CallerInfo(String callerPackageName, UserHandle user) {} boolean createBond( @@ -5294,16 +3106,13 @@ public class AdapterService extends Service { public int getConnectionState(BluetoothDevice device) { final String address = device.getAddress(); - if (Flags.apiGetConnectionStateUsingIdentityAddress()) { - int connectionState = mNativeInterface.getConnectionState(getBytesFromAddress(address)); - final String identityAddress = getIdentityAddress(address); - if (identityAddress != null) { - connectionState |= - mNativeInterface.getConnectionState(getBytesFromAddress(identityAddress)); - } - return connectionState; + int connectionState = mNativeInterface.getConnectionState(getBytesFromAddress(address)); + final String identityAddress = getIdentityAddress(address); + if (identityAddress != null) { + connectionState |= + mNativeInterface.getConnectionState(getBytesFromAddress(identityAddress)); } - return mNativeInterface.getConnectionState(getBytesFromAddress(address)); + return connectionState; } int getConnectionHandle(BluetoothDevice device, int transport) { @@ -5388,35 +3197,32 @@ public class AdapterService extends Service { Log.e(TAG, "setActiveDevice: Bluetooth is not enabled"); return false; } - boolean setA2dp = false; boolean setHeadset = false; + boolean setA2dp = false; // Determine for which profiles we want to set device as our active device switch (profiles) { - case BluetoothAdapter.ACTIVE_DEVICE_AUDIO: - setA2dp = true; - break; - case BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL: + case BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL -> setHeadset = true; + case BluetoothAdapter.ACTIVE_DEVICE_AUDIO -> setA2dp = true; + case BluetoothAdapter.ACTIVE_DEVICE_ALL -> { setHeadset = true; - break; - case BluetoothAdapter.ACTIVE_DEVICE_ALL: setA2dp = true; - setHeadset = true; - break; - default: + } + default -> { return false; + } } - boolean a2dpSupported = - mA2dpService != null - && (device == null - || mA2dpService.getConnectionPolicy(device) - == CONNECTION_POLICY_ALLOWED); boolean hfpSupported = mHeadsetService != null && (device == null || mHeadsetService.getConnectionPolicy(device) == CONNECTION_POLICY_ALLOWED); + boolean a2dpSupported = + mA2dpService != null + && (device == null + || mA2dpService.getConnectionPolicy(device) + == CONNECTION_POLICY_ALLOWED); boolean leAudioSupported = mLeAudioService != null && (device == null @@ -5439,6 +3245,12 @@ public class AdapterService extends Service { } } + // Order matters, some devices do not accept A2DP connection before HFP connection + if (setHeadset && hfpSupported) { + Log.i(TAG, "setActiveDevice: Setting active Headset " + device); + mHeadsetService.setActiveDevice(device); + } + if (setA2dp && a2dpSupported) { Log.i(TAG, "setActiveDevice: Setting active A2dp device " + device); if (device == null) { @@ -5470,11 +3282,6 @@ public class AdapterService extends Service { } } - if (setHeadset && hfpSupported) { - Log.i(TAG, "setActiveDevice: Setting active Headset " + device); - mHeadsetService.setActiveDevice(device); - } - return true; } @@ -5489,8 +3296,8 @@ public class AdapterService extends Service { if (mLeAudioService == null) { return false; } - boolean a2dpSupported = isProfileSupported(leAudioDevice, BluetoothProfile.A2DP); boolean hfpSupported = isProfileSupported(leAudioDevice, BluetoothProfile.HEADSET); + boolean a2dpSupported = isProfileSupported(leAudioDevice, BluetoothProfile.A2DP); List<BluetoothDevice> groupDevices = mLeAudioService.getGroupDevices(leAudioDevice); if (hfpSupported && mHeadsetService != null) { @@ -5596,26 +3403,11 @@ public class AdapterService extends Service { return BluetoothStatusCodes.SUCCESS; } - /** - * Connect all supported bluetooth profiles between the local and remote device - * - * @param device is the remote device with which to connect all supported profiles - */ + /** All profile toggles are disabled, so connects all supported profiles */ void connectAllSupportedProfiles(BluetoothDevice device) { int numProfilesConnected = 0; - // All profile toggles disabled, so connects all supported profiles - if (mA2dpService != null && isProfileSupported(device, BluetoothProfile.A2DP)) { - Log.i(TAG, "connectAllSupportedProfiles: Connecting A2dp"); - // Set connection policy also connects the profile with CONNECTION_POLICY_ALLOWED - mA2dpService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED); - numProfilesConnected++; - } - if (mA2dpSinkService != null && isProfileSupported(device, BluetoothProfile.A2DP_SINK)) { - Log.i(TAG, "connectAllSupportedProfiles: Connecting A2dp Sink"); - mA2dpSinkService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED); - numProfilesConnected++; - } + // Order matters, some devices do not accept A2DP connection before HFP connection if (mHeadsetService != null && isProfileSupported(device, BluetoothProfile.HEADSET)) { Log.i(TAG, "connectAllSupportedProfiles: Connecting Headset Profile"); mHeadsetService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED); @@ -5627,6 +3419,17 @@ public class AdapterService extends Service { mHeadsetClientService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED); numProfilesConnected++; } + if (mA2dpService != null && isProfileSupported(device, BluetoothProfile.A2DP)) { + Log.i(TAG, "connectAllSupportedProfiles: Connecting A2dp"); + // Set connection policy also connects the profile with CONNECTION_POLICY_ALLOWED + mA2dpService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED); + numProfilesConnected++; + } + if (mA2dpSinkService != null && isProfileSupported(device, BluetoothProfile.A2DP_SINK)) { + Log.i(TAG, "connectAllSupportedProfiles: Connecting A2dp Sink"); + mA2dpSinkService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED); + numProfilesConnected++; + } if (mMapClientService != null && isProfileSupported(device, BluetoothProfile.MAP_CLIENT)) { Log.i(TAG, "connectAllSupportedProfiles: Connecting MAP"); mMapClientService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED); @@ -5715,18 +3518,6 @@ public class AdapterService extends Service { return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } - if (mA2dpService != null - && (mA2dpService.getConnectionState(device) == STATE_CONNECTED - || mA2dpService.getConnectionState(device) == STATE_CONNECTING)) { - Log.i(TAG, "disconnectAllEnabledProfiles: Disconnecting A2dp"); - mA2dpService.disconnect(device); - } - if (mA2dpSinkService != null - && (mA2dpSinkService.getConnectionState(device) == STATE_CONNECTED - || mA2dpSinkService.getConnectionState(device) == STATE_CONNECTING)) { - Log.i(TAG, "disconnectAllEnabledProfiles: Disconnecting A2dp Sink"); - mA2dpSinkService.disconnect(device); - } if (mHeadsetService != null && (mHeadsetService.getConnectionState(device) == STATE_CONNECTED || mHeadsetService.getConnectionState(device) == STATE_CONNECTING)) { @@ -5739,6 +3530,18 @@ public class AdapterService extends Service { Log.i(TAG, "disconnectAllEnabledProfiles: Disconnecting HFP"); mHeadsetClientService.disconnect(device); } + if (mA2dpService != null + && (mA2dpService.getConnectionState(device) == STATE_CONNECTED + || mA2dpService.getConnectionState(device) == STATE_CONNECTING)) { + Log.i(TAG, "disconnectAllEnabledProfiles: Disconnecting A2dp"); + mA2dpService.disconnect(device); + } + if (mA2dpSinkService != null + && (mA2dpSinkService.getConnectionState(device) == STATE_CONNECTED + || mA2dpSinkService.getConnectionState(device) == STATE_CONNECTING)) { + Log.i(TAG, "disconnectAllEnabledProfiles: Disconnecting A2dp Sink"); + mA2dpSinkService.disconnect(device); + } if (mMapClientService != null && (mMapClientService.getConnectionState(device) == STATE_CONNECTED || mMapClientService.getConnectionState(device) == STATE_CONNECTING)) { @@ -6125,27 +3928,22 @@ public class AdapterService extends Service { mLocalCallbacks.remove(callback); } - @VisibleForTesting void registerRemoteCallback(IBluetoothCallback callback) { mSystemServerCallbacks.register(callback); } - @VisibleForTesting void unregisterRemoteCallback(IBluetoothCallback callback) { mSystemServerCallbacks.unregister(callback); } - @VisibleForTesting void bleOnToOn() { mAdapterStateMachine.sendMessage(AdapterState.USER_TURN_ON); } - @VisibleForTesting void bleOnToOff() { mAdapterStateMachine.sendMessage(AdapterState.BLE_TURN_OFF); } - @VisibleForTesting boolean factoryReset() { mDatabaseManager.factoryReset(); @@ -6164,12 +3962,11 @@ public class AdapterService extends Service { return mNativeInterface.factoryReset(); } - @VisibleForTesting int getScanMode() { return mScanMode; } - private boolean setScanMode(int mode, String from) { + boolean setScanMode(int mode, String from) { mScanModeChanges.add(from + ": " + scanModeName(mode)); if (!mNativeInterface.setScanMode(convertScanModeToHal(mode))) { return false; @@ -6183,7 +3980,6 @@ public class AdapterService extends Service { return true; } - @VisibleForTesting BluetoothActivityEnergyInfo reportActivityInfo() { if (mAdapterProperties.getState() != BluetoothAdapter.STATE_ON || !mAdapterProperties.isActivityAndEnergyReportingSupported()) { @@ -6398,12 +4194,12 @@ public class AdapterService extends Service { /** Handle Bluetooth profiles when bond state changes with a {@link BluetoothDevice} */ public void handleBondStateChanged(BluetoothDevice device, int fromState, int toState) { - if (mA2dpService != null && mA2dpService.isAvailable()) { - mA2dpService.handleBondStateChanged(device, fromState, toState); - } if (mHeadsetService != null && mHeadsetService.isAvailable()) { mHeadsetService.handleBondStateChanged(device, fromState, toState); } + if (mA2dpService != null && mA2dpService.isAvailable()) { + mA2dpService.handleBondStateChanged(device, fromState, toState); + } if (mLeAudioService != null && mLeAudioService.isAvailable()) { mLeAudioService.handleBondStateChanged(device, fromState, toState); } @@ -6629,10 +4425,6 @@ public class AdapterService extends Service { return BluetoothProperties.getHardwareOperatingVoltageMv().orElse(0) / 1000.0; } - public RemoteDevices getRemoteDevices() { - return mRemoteDevices; - } - private static String scanModeName(int scanMode) { return switch (scanMode) { case SCAN_MODE_NONE -> "SCAN_MODE_NONE"; diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterServiceBinder.java b/android/app/src/com/android/bluetooth/btservice/AdapterServiceBinder.java new file mode 100644 index 0000000000..aff6642b7d --- /dev/null +++ b/android/app/src/com/android/bluetooth/btservice/AdapterServiceBinder.java @@ -0,0 +1,2262 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.btservice; + +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.Manifest.permission.DUMP; +import static android.Manifest.permission.LOCAL_MAC_ADDRESS; +import static android.Manifest.permission.MODIFY_PHONE_STATE; +import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE; +import static android.bluetooth.BluetoothDevice.TRANSPORT_AUTO; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import static com.android.bluetooth.ChangeIds.ENFORCE_CONNECT; +import static com.android.bluetooth.Utils.callerIsSystem; +import static com.android.bluetooth.Utils.callerIsSystemOrActiveOrManagedUser; +import static com.android.bluetooth.Utils.checkConnectPermissionForDataDelivery; +import static com.android.bluetooth.Utils.checkScanPermissionForDataDelivery; +import static com.android.bluetooth.Utils.getBytesFromAddress; +import static com.android.bluetooth.Utils.getUidPidString; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.app.PendingIntent; +import android.app.compat.CompatChanges; +import android.bluetooth.BluetoothActivityEnergyInfo; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothAdapter.ActiveDeviceProfile; +import android.bluetooth.BluetoothAdapter.ActiveDeviceUse; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothDevice.BluetoothAddress; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothProtoEnums; +import android.bluetooth.BluetoothSinkAudioPolicy; +import android.bluetooth.BluetoothStatusCodes; +import android.bluetooth.IBluetooth; +import android.bluetooth.IBluetoothActivityEnergyInfoListener; +import android.bluetooth.IBluetoothCallback; +import android.bluetooth.IBluetoothConnectionCallback; +import android.bluetooth.IBluetoothHciVendorSpecificCallback; +import android.bluetooth.IBluetoothMetadataListener; +import android.bluetooth.IBluetoothOobDataCallback; +import android.bluetooth.IBluetoothPreferredAudioProfilesCallback; +import android.bluetooth.IBluetoothQualityReportReadyCallback; +import android.bluetooth.IBluetoothSocketManager; +import android.bluetooth.IncomingRfcommSocketInfo; +import android.bluetooth.OobData; +import android.content.AttributionSource; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Message; +import android.os.ParcelUuid; +import android.os.Process; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.util.Log; + +import com.android.bluetooth.BluetoothStatsLog; +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; +import com.android.bluetooth.flags.Flags; +import com.android.modules.expresslog.Counter; + +import libcore.util.SneakyThrow; + +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +/** + * There is no leak of this binder since it is never re-used and the process is systematically + * killed + */ +class AdapterServiceBinder extends IBluetooth.Stub { + private static final String TAG = + Utils.TAG_PREFIX_BLUETOOTH + AdapterServiceBinder.class.getSimpleName(); + + private static final int MIN_ADVT_INSTANCES_FOR_MA = 5; + private static final int MIN_OFFLOADED_FILTERS = 10; + private static final int MIN_OFFLOADED_SCAN_STORAGE_BYTES = 1024; + + private final AdapterService mService; + + AdapterServiceBinder(AdapterService svc) { + mService = svc; + } + + public AdapterService getService() { + if (!mService.isAvailable()) { + return null; + } + return mService; + } + + @Override + public int getState() { + AdapterService service = getService(); + if (service == null) { + return BluetoothAdapter.STATE_OFF; + } + + return service.getState(); + } + + @Override + public void killBluetoothProcess() { + mService.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); + + Runnable killAction = + () -> { + if (Flags.killInsteadOfExit()) { + Log.i(TAG, "killBluetoothProcess: Calling killProcess(myPid())"); + Process.killProcess(Process.myPid()); + } else { + Log.i(TAG, "killBluetoothProcess: Calling System.exit"); + System.exit(0); + } + }; + + // Post on the main handler to let the cleanup complete before calling exit + mService.getHandler().post(killAction); + + try { + // Wait for Bluetooth to be killed from its main thread + Thread.sleep(1_000); // SystemServer is waiting 2000 ms, we need to wait less here + } catch (InterruptedException e) { + Log.e(TAG, "killBluetoothProcess: Interrupted while waiting for kill"); + } + + // Bluetooth cannot be killed on the main thread; it is in a deadLock. + // Trying to recover by killing the Bluetooth from the binder thread. + // This is bad :( + Counter.logIncrement("bluetooth.value_kill_from_binder_thread"); + Log.wtf(TAG, "Failed to kill Bluetooth using its main thread. Trying from binder"); + killAction.run(); + } + + @Override + public void offToBleOn(boolean quietMode, AttributionSource source) { + AdapterService service = getService(); + if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG, "offToBleOn")) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.offToBleOn(quietMode); + } + + @Override + public void onToBleOn(AttributionSource source) { + AdapterService service = getService(); + if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG, "onToBleOn")) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.onToBleOn(); + } + + @Override + public String getAddress(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getAddress") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getAddress")) { + return null; + } + + service.enforceCallingOrSelfPermission(LOCAL_MAC_ADDRESS, null); + return Utils.getAddressStringFromByte(service.getAdapterProperties().getAddress()); + } + + @Override + public List<ParcelUuid> getUuids(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getUuids") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getUuids")) { + return Collections.emptyList(); + } + + ParcelUuid[] parcels = service.getAdapterProperties().getUuids(); + if (parcels == null) { + parcels = new ParcelUuid[0]; + } + return Arrays.asList(parcels); + } + + @Override + public String getIdentityAddress(String address) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getIdentityAddress") + || !checkConnectPermissionForDataDelivery( + service, + Utils.getCallingAttributionSource(mService), + TAG, + "getIdentityAddress")) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getIdentityAddress(address); + } + + @Override + @NonNull + public BluetoothAddress getIdentityAddressWithType(@NonNull String address) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getIdentityAddressWithType") + || !checkConnectPermissionForDataDelivery( + service, + Utils.getCallingAttributionSource(mService), + TAG, + "getIdentityAddressWithType")) { + return new BluetoothAddress(null, BluetoothDevice.ADDRESS_TYPE_UNKNOWN); + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getIdentityAddressWithType(address); + } + + @Override + public String getName(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getName") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getName")) { + return null; + } + + return service.getName(); + } + + @Override + public int getNameLengthForAdvertise(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getNameLengthForAdvertise") + || !Utils.checkAdvertisePermissionForDataDelivery(service, source, TAG)) { + return -1; + } + + return service.getNameLengthForAdvertise(); + } + + @Override + public boolean setName(String name, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setName") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "setName")) { + return false; + } + + if (Flags.emptyNamesAreInvalid()) { + requireNonNull(name); + name = name.trim(); + if (name.isEmpty()) { + throw new IllegalArgumentException("Empty names are not valid"); + } + } + + Log.d(TAG, "AdapterServiceBinder.setName(" + name + ")"); + return service.getAdapterProperties().setName(name); + } + + @Override + public int getScanMode(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getScanMode") + || !checkScanPermissionForDataDelivery(service, source, TAG, "getScanMode")) { + return SCAN_MODE_NONE; + } + + return service.getScanMode(); + } + + @Override + public int setScanMode(int mode, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setScanMode") + || !checkScanPermissionForDataDelivery(service, source, TAG, "setScanMode")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + String logCaller = getUidPidString() + " packageName=" + source.getPackageName(); + CompletableFuture<Boolean> future = new CompletableFuture<>(); + mService.getHandler() + .post( + () -> + future.complete( + service.getState() == BluetoothAdapter.STATE_ON + && service.setScanMode(mode, logCaller))); + return future.join() ? BluetoothStatusCodes.SUCCESS : BluetoothStatusCodes.ERROR_UNKNOWN; + } + + @Override + public long getDiscoverableTimeout(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getDiscoverableTimeout") + || !checkScanPermissionForDataDelivery( + service, source, TAG, "getDiscoverableTimeout")) { + return -1; + } + + return service.getAdapterProperties().getDiscoverableTimeout(); + } + + @Override + public int setDiscoverableTimeout(long timeout, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setDiscoverableTimeout") + || !checkScanPermissionForDataDelivery( + service, source, TAG, "setDiscoverableTimeout")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getAdapterProperties().setDiscoverableTimeout((int) timeout) + ? BluetoothStatusCodes.SUCCESS + : BluetoothStatusCodes.ERROR_UNKNOWN; + } + + @Override + public boolean startDiscovery(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "startDiscovery") + || !checkScanPermissionForDataDelivery(service, source, TAG, "startDiscovery")) { + return false; + } + + Log.i(TAG, "startDiscovery: from " + getUidPidString()); + return service.startDiscovery(source); + } + + @Override + public boolean cancelDiscovery(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "cancelDiscovery") + || !checkScanPermissionForDataDelivery(service, source, TAG, "cancelDiscovery")) { + return false; + } + + Log.i(TAG, "cancelDiscovery: from " + getUidPidString()); + return service.getNative().cancelDiscovery(); + } + + @Override + public boolean isDiscovering(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "isDiscovering") + || !checkScanPermissionForDataDelivery(service, source, TAG, "isDiscovering")) { + return false; + } + + return service.getAdapterProperties().isDiscovering(); + } + + @Override + public long getDiscoveryEndMillis(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getDiscoveryEndMillis") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getDiscoveryEndMillis")) { + return -1; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + return service.getAdapterProperties().discoveryEndMillis(); + } + + @Override + public List<BluetoothDevice> getMostRecentlyConnectedDevices(AttributionSource source) { + // don't check caller, may be called from system UI + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getMostRecentlyConnectedDevices")) { + return Collections.emptyList(); + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + return service.getDatabaseManager().getMostRecentlyConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getBondedDevices(AttributionSource source) { + // don't check caller, may be called from system UI + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getBondedDevices")) { + return Collections.emptyList(); + } + + return Arrays.asList(service.getBondedDevices()); + } + + @Override + public int getAdapterConnectionState() { + // don't check caller, may be called from system UI + AdapterService service = getService(); + if (service == null) { + return BluetoothAdapter.STATE_DISCONNECTED; + } + + return service.getAdapterProperties().getConnectionState(); + } + + /** + * This method has an associated binder cache. The invalidation methods must be changed if the + * logic behind this method changes. + */ + @Override + public int getProfileConnectionState(int profile, AttributionSource source) { + AdapterService service = getService(); + boolean checkConnect = false; + final int callingUid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); + try { + checkConnect = CompatChanges.isChangeEnabled(ENFORCE_CONNECT, callingUid); + } finally { + Binder.restoreCallingIdentity(token); + } + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getProfileConnectionState") + || (checkConnect + && !checkConnectPermissionForDataDelivery( + service, source, TAG, "getProfileConnectionState"))) { + return STATE_DISCONNECTED; + } + + return service.getAdapterProperties().getProfileConnectionState(profile); + } + + @Override + public boolean createBond(BluetoothDevice device, int transport, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "createBond") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "createBond")) { + return false; + } + + Log.i( + TAG, + "createBond:" + + (" device=" + device) + + (" transport=" + transport) + + (" from " + getUidPidString())); + return service.createBond(device, transport, null, null, source.getPackageName()); + } + + @Override + public boolean createBondOutOfBand( + BluetoothDevice device, + int transport, + OobData remoteP192Data, + OobData remoteP256Data, + AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "createBondOutOfBand") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "createBondOutOfBand")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + Log.i( + TAG, + "createBondOutOfBand:" + + (" device=" + device) + + (" transport=" + transport) + + (" from " + getUidPidString())); + return service.createBond( + device, transport, remoteP192Data, remoteP256Data, source.getPackageName()); + } + + @Override + public boolean cancelBondProcess(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "cancelBondProcess") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "cancelBondProcess")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + Log.i(TAG, "cancelBondProcess: device=" + device + ", from " + getUidPidString()); + + DeviceProperties deviceProp = service.getRemoteDevices().getDeviceProperties(device); + if (deviceProp != null) { + deviceProp.setBondingInitiatedLocally(false); + } + + service.logUserBondResponse(device, false, source); + return service.getNative().cancelBond(getBytesFromAddress(device.getAddress())); + } + + @Override + public boolean removeBond(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "removeBond") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "removeBond")) { + return false; + } + + Log.i(TAG, "removeBond: device=" + device + ", from " + getUidPidString()); + + DeviceProperties deviceProp = service.getRemoteDevices().getDeviceProperties(device); + if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) { + Log.w( + TAG, + device + + " cannot be removed since " + + ((deviceProp == null) + ? "properties are empty" + : "bond state is " + deviceProp.getBondState())); + return false; + } + service.logUserBondResponse(device, false, source); + service.getBondAttemptCallerInfo().remove(device.getAddress()); + service.getPhonePolicy().ifPresent(policy -> policy.onRemoveBondRequest(device)); + deviceProp.setBondingInitiatedLocally(false); + + Message msg = service.getBondStateMachine().obtainMessage(BondStateMachine.REMOVE_BOND); + msg.obj = device; + service.getBondStateMachine().sendMessage(msg); + return true; + } + + @Override + public int getBondState(BluetoothDevice device, AttributionSource source) { + // don't check caller, may be called from system UI + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getBondState")) { + return BluetoothDevice.BOND_NONE; + } + + return service.getBondState(device); + } + + @Override + public boolean isBondingInitiatedLocally(BluetoothDevice device, AttributionSource source) { + // don't check caller, may be called from system UI + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "isBondingInitiatedLocally")) { + return false; + } + + DeviceProperties deviceProp = service.getRemoteDevices().getDeviceProperties(device); + return deviceProp != null && deviceProp.isBondingInitiatedLocally(); + } + + @Override + public void generateLocalOobData( + int transport, IBluetoothOobDataCallback callback, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "generateLocalOobData") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "generateLocalOobData")) { + return; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.generateLocalOobData(transport, callback); + } + + @Override + public long getSupportedProfiles(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getSupportedProfiles")) { + return 0; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return Config.getSupportedProfilesBitMask(); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getConnectionState")) { + return BluetoothDevice.CONNECTION_STATE_DISCONNECTED; + } + + return service.getConnectionState(device); + } + + @Override + public int getConnectionHandle( + BluetoothDevice device, int transport, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getConnectionHandle") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getConnectionHandle")) { + return BluetoothDevice.ERROR; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionHandle(device, transport); + } + + @Override + public boolean canBondWithoutDialog(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "canBondWithoutDialog")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.canBondWithoutDialog(device); + } + + @Override + public String getPackageNameOfBondingApplication( + BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + + if (service == null + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getPackageNameOfBondingApplication")) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getPackageNameOfBondingApplication(device); + } + + @Override + public boolean removeActiveDevice(@ActiveDeviceUse int profiles, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "removeActiveDevice") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "removeActiveDevice")) { + return false; + } + + service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + Log.i(TAG, "removeActiveDevice: profiles=" + profiles + ", from " + getUidPidString()); + return service.setActiveDevice(null, profiles); + } + + @Override + public boolean setActiveDevice( + BluetoothDevice device, @ActiveDeviceUse int profiles, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setActiveDevice") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "setActiveDevice")) { + return false; + } + + service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + Log.i( + TAG, + "setActiveDevice: device=" + + device + + ", profiles=" + + profiles + + ", from " + + getUidPidString()); + + return service.setActiveDevice(device, profiles); + } + + @Override + public List<BluetoothDevice> getActiveDevices( + @ActiveDeviceProfile int profile, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getActiveDevices") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getActiveDevices")) { + return Collections.emptyList(); + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getActiveDevices(profile); + } + + @Override + public int connectAllEnabledProfiles(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null || !service.isEnabled()) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "connectAllEnabledProfiles")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + if (device == null) { + throw new IllegalArgumentException("device cannot be null"); + } + if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "connectAllEnabledProfiles")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + Log.i(TAG, "connectAllEnabledProfiles: device=" + device + ", from " + getUidPidString()); + MetricsLogger.getInstance() + .logBluetoothEvent( + device, + BluetoothStatsLog + .BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__INITIATOR_CONNECTION, + BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__START, + source.getUid()); + + try { + return service.connectAllEnabledProfiles(device); + } catch (Exception e) { + Log.v(TAG, "connectAllEnabledProfiles() failed", e); + SneakyThrow.sneakyThrow(e); + throw new RuntimeException(e); + } + } + + @Override + public int disconnectAllEnabledProfiles(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "disconnectAllEnabledProfiles")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + if (device == null) { + throw new IllegalArgumentException("device cannot be null"); + } + if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "disconnectAllEnabledProfiles")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + Log.i( + TAG, + "disconnectAllEnabledProfiles: device=" + device + ", from " + getUidPidString()); + + try { + return service.disconnectAllEnabledProfiles(device); + } catch (Exception e) { + Log.v(TAG, "disconnectAllEnabledProfiles() failed", e); + SneakyThrow.sneakyThrow(e); + throw new RuntimeException(e); + } + } + + @Override + public String getRemoteName(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getRemoteName") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getRemoteName")) { + return null; + } + + return service.getRemoteName(device); + } + + @Override + public int getRemoteType(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getRemoteType") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getRemoteType")) { + return BluetoothDevice.DEVICE_TYPE_UNKNOWN; + } + + return service.getRemoteType(device); + } + + @Override + public String getRemoteAlias(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getRemoteAlias") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getRemoteAlias")) { + return null; + } + + DeviceProperties deviceProp = service.getRemoteDevices().getDeviceProperties(device); + return deviceProp != null ? deviceProp.getAlias() : null; + } + + @Override + public int setRemoteAlias(BluetoothDevice device, String name, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "setRemoteAlias")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + if (name != null && name.isEmpty()) { + throw new IllegalArgumentException("alias cannot be the empty string"); + } + + if (!checkConnectPermissionForDataDelivery(service, source, TAG, "setRemoteAlias")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + Utils.enforceCdmAssociationIfNotBluetoothPrivileged( + service, service.getCompanionDeviceManager(), source, device); + + DeviceProperties deviceProp = service.getRemoteDevices().getDeviceProperties(device); + if (deviceProp == null) { + return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED; + } + deviceProp.setAlias(device, name); + return BluetoothStatusCodes.SUCCESS; + } + + @Override + public int getRemoteClass(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getRemoteClass") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getRemoteClass")) { + return 0; + } + + return service.getRemoteClass(device); + } + + @Override + public List<ParcelUuid> getRemoteUuids(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getRemoteUuids") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getRemoteUuids")) { + return Collections.emptyList(); + } + + final ParcelUuid[] parcels = service.getRemoteUuids(device); + if (parcels == null) { + return null; + } + return Arrays.asList(parcels); + } + + @Override + public boolean fetchRemoteUuids( + BluetoothDevice device, int transport, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "fetchRemoteUuids") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "fetchRemoteUuids")) { + return false; + } + if (transport != TRANSPORT_AUTO) { + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + } + + Log.i( + TAG, + "fetchRemoteUuids: device=" + + device + + ", transport=" + + transport + + ", from " + + getUidPidString()); + + service.getRemoteDevices().fetchUuids(device, transport); + MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.SDP_FETCH_UUID_REQUEST, 1); + return true; + } + + @Override + public boolean setPin( + BluetoothDevice device, + boolean accept, + int len, + byte[] pinCode, + AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setPin") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "setPin")) { + return false; + } + + DeviceProperties deviceProp = service.getRemoteDevices().getDeviceProperties(device); + // Only allow setting a pin in bonding state, or bonded state in case of security + // upgrade. + if (deviceProp == null || !deviceProp.isBondingOrBonded()) { + Log.e(TAG, "setPin: device=" + device + ", not bonding"); + return false; + } + if (pinCode.length != len) { + android.util.EventLog.writeEvent( + 0x534e4554, "139287605", -1, "PIN code length mismatch"); + return false; + } + service.logUserBondResponse(device, accept, source); + Log.i( + TAG, + "setPin: device=" + device + ", accept=" + accept + ", from " + getUidPidString()); + return service.getNative() + .pinReply(getBytesFromAddress(device.getAddress()), accept, len, pinCode); + } + + @Override + public boolean setPasskey( + BluetoothDevice device, + boolean accept, + int len, + byte[] passkey, + AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setPasskey") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "setPasskey")) { + return false; + } + + DeviceProperties deviceProp = service.getRemoteDevices().getDeviceProperties(device); + if (deviceProp == null || !deviceProp.isBonding()) { + Log.e(TAG, "setPasskey: device=" + device + ", not bonding"); + return false; + } + if (passkey.length != len) { + android.util.EventLog.writeEvent( + 0x534e4554, "139287605", -1, "Passkey length mismatch"); + return false; + } + service.logUserBondResponse(device, accept, source); + Log.i( + TAG, + "setPasskey: device=" + + device + + ", accept=" + + accept + + ", from " + + getUidPidString()); + + return service.getNative() + .sspReply( + getBytesFromAddress(device.getAddress()), + AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, + accept, + Utils.byteArrayToInt(passkey)); + } + + @Override + public boolean setPairingConfirmation( + BluetoothDevice device, boolean accept, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setPairingConfirmation") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "setPairingConfirmation")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + DeviceProperties deviceProp = service.getRemoteDevices().getDeviceProperties(device); + if (deviceProp == null || !deviceProp.isBonding()) { + Log.e(TAG, "setPairingConfirmation: device=" + device + ", not bonding"); + return false; + } + service.logUserBondResponse(device, accept, source); + Log.i( + TAG, + "setPairingConfirmation: device=" + + device + + ", accept=" + + accept + + ", from " + + getUidPidString()); + + return service.getNative() + .sspReply( + getBytesFromAddress(device.getAddress()), + AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION, + accept, + 0); + } + + @Override + public boolean getSilenceMode(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getSilenceMode") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getSilenceMode")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getSilenceDeviceManager().getSilenceMode(device); + } + + @Override + public boolean setSilenceMode( + BluetoothDevice device, boolean silence, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setSilenceMode") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "setSilenceMode")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.getSilenceDeviceManager().setSilenceMode(device, silence); + return true; + } + + @Override + public int getPhonebookAccessPermission(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser( + service, TAG, "getPhonebookAccessPermission") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getPhonebookAccessPermission")) { + return BluetoothDevice.ACCESS_UNKNOWN; + } + + return service.getPhonebookAccessPermission(device); + } + + @Override + public boolean setPhonebookAccessPermission( + BluetoothDevice device, int value, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser( + service, TAG, "setPhonebookAccessPermission") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "setPhonebookAccessPermission")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setPhonebookAccessPermission(device, value); + return true; + } + + @Override + public int getMessageAccessPermission(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getMessageAccessPermission") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getMessageAccessPermission")) { + return BluetoothDevice.ACCESS_UNKNOWN; + } + + return service.getMessageAccessPermission(device); + } + + @Override + public boolean setMessageAccessPermission( + BluetoothDevice device, int value, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setMessageAccessPermission") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "setMessageAccessPermission")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setMessageAccessPermission(device, value); + return true; + } + + @Override + public int getSimAccessPermission(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getSimAccessPermission") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getSimAccessPermission")) { + return BluetoothDevice.ACCESS_UNKNOWN; + } + + return service.getSimAccessPermission(device); + } + + @Override + public boolean setSimAccessPermission( + BluetoothDevice device, int value, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setSimAccessPermission") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "setSimAccessPermission")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setSimAccessPermission(device, value); + return true; + } + + @Override + public void logL2capcocServerConnection( + BluetoothDevice device, + int port, + boolean isSecured, + int result, + long socketCreationTimeMillis, + long socketCreationLatencyMillis, + long socketConnectionTimeMillis, + long timeoutMillis) { + AdapterService service = getService(); + if (service == null) { + return; + } + service.logL2capcocServerConnection( + device, + port, + isSecured, + result, + socketCreationTimeMillis, + socketCreationLatencyMillis, + socketConnectionTimeMillis, + timeoutMillis, + Binder.getCallingUid()); + } + + @Override + public IBluetoothSocketManager getSocketManager() { + AdapterService service = getService(); + if (service == null) { + return null; + } + + return IBluetoothSocketManager.Stub.asInterface(service.getBluetoothSocketManagerBinder()); + } + + @Override + public void logL2capcocClientConnection( + BluetoothDevice device, + int port, + boolean isSecured, + int result, + long socketCreationTimeNanos, + long socketCreationLatencyNanos, + long socketConnectionTimeNanos) { + AdapterService service = getService(); + if (service == null) { + return; + } + service.logL2capcocClientConnection( + device, + port, + isSecured, + result, + socketCreationTimeNanos, + socketCreationLatencyNanos, + socketConnectionTimeNanos, + Binder.getCallingUid()); + } + + @Override + public void logRfcommConnectionAttempt( + BluetoothDevice device, + boolean isSecured, + int resultCode, + long socketCreationTimeNanos, + boolean isSerialPort) { + AdapterService service = getService(); + if (service == null) { + return; + } + service.logRfcommConnectionAttempt( + device, + isSecured, + resultCode, + socketCreationTimeNanos, + isSerialPort, + Binder.getCallingUid()); + } + + @Override + public boolean sdpSearch(BluetoothDevice device, ParcelUuid uuid, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "sdpSearch") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "sdpSearch")) { + return false; + } + return service.sdpSearch(device, uuid); + } + + @Override + public int getBatteryLevel(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getBatteryLevel") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getBatteryLevel")) { + return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + } + + DeviceProperties deviceProp = service.getRemoteDevices().getDeviceProperties(device); + if (deviceProp == null) { + return BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + } + return deviceProp.getBatteryLevel(); + } + + @Override + public int getMaxConnectedAudioDevices(AttributionSource source) { + // don't check caller, may be called from system UI + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getMaxConnectedAudioDevices")) { + return -1; + } + + return service.getMaxConnectedAudioDevices(); + } + + @Override + public boolean factoryReset(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery(service, source, TAG, "factoryReset")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.factoryReset(); + } + + @Override + public void registerBluetoothConnectionCallback( + IBluetoothConnectionCallback callback, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser( + service, TAG, "registerBluetoothConnectionCallback") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "registerBluetoothConnectionCallback")) { + return; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.getBluetoothConnectionCallbacks().register(callback); + } + + @Override + public void unregisterBluetoothConnectionCallback( + IBluetoothConnectionCallback callback, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser( + service, TAG, "unregisterBluetoothConnectionCallback") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "unregisterBluetoothConnectionCallback")) { + return; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.getBluetoothConnectionCallbacks().unregister(callback); + } + + @Override + public void registerCallback(IBluetoothCallback callback, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "registerCallback") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "registerCallback")) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.registerRemoteCallback(callback); + } + + @Override + public void unregisterCallback(IBluetoothCallback callback, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "unregisterCallback") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "unregisterCallback")) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.unregisterRemoteCallback(callback); + } + + @Override + public boolean isMultiAdvertisementSupported() { + AdapterService service = getService(); + if (service == null) { + return false; + } + + int val = service.getAdapterProperties().getNumOfAdvertisementInstancesSupported(); + return val >= MIN_ADVT_INSTANCES_FOR_MA; + } + + /** + * This method has an associated binder cache. The invalidation methods must be changed if the + * logic behind this method changes. + */ + @Override + public boolean isOffloadedFilteringSupported() { + AdapterService service = getService(); + if (service == null) { + return false; + } + + int val = service.getNumOfOffloadedScanFilterSupported(); + return val >= MIN_OFFLOADED_FILTERS; + } + + @Override + public boolean isOffloadedScanBatchingSupported() { + AdapterService service = getService(); + if (service == null) { + return false; + } + + int val = service.getOffloadedScanResultStorage(); + return val >= MIN_OFFLOADED_SCAN_STORAGE_BYTES; + } + + @Override + public boolean isLe2MPhySupported() { + AdapterService service = getService(); + if (service == null) { + return false; + } + + return service.isLe2MPhySupported(); + } + + @Override + public boolean isLeCodedPhySupported() { + AdapterService service = getService(); + if (service == null) { + return false; + } + + return service.isLeCodedPhySupported(); + } + + @Override + public boolean isLeExtendedAdvertisingSupported() { + AdapterService service = getService(); + if (service == null) { + return false; + } + + return service.isLeExtendedAdvertisingSupported(); + } + + @Override + public boolean isLePeriodicAdvertisingSupported() { + AdapterService service = getService(); + if (service == null) { + return false; + } + + return service.isLePeriodicAdvertisingSupported(); + } + + @Override + public int isLeAudioSupported() { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + + Set<Integer> supportedProfileServices = + Arrays.stream(Config.getSupportedProfiles()).boxed().collect(Collectors.toSet()); + int[] leAudioUnicastProfiles = Config.getLeAudioUnicastProfiles(); + + if (Arrays.stream(leAudioUnicastProfiles).allMatch(supportedProfileServices::contains)) { + return BluetoothStatusCodes.FEATURE_SUPPORTED; + } + + return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; + } + + @Override + public int isLeAudioBroadcastSourceSupported() { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + + long supportBitMask = Config.getSupportedProfilesBitMask(); + if ((supportBitMask & (1 << BluetoothProfile.LE_AUDIO_BROADCAST)) != 0) { + return BluetoothStatusCodes.FEATURE_SUPPORTED; + } + + return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; + } + + @Override + public int isLeAudioBroadcastAssistantSupported() { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + + int[] supportedProfileServices = Config.getSupportedProfiles(); + + if (Arrays.stream(supportedProfileServices) + .anyMatch( + profileId -> profileId == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)) { + return BluetoothStatusCodes.FEATURE_SUPPORTED; + } + + return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; + } + + @Override + public int isDistanceMeasurementSupported(AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } else if (!callerIsSystemOrActiveOrManagedUser( + service, TAG, "isDistanceMeasurementSupported")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } else if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "isDistanceMeasurementSupported")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return BluetoothStatusCodes.FEATURE_SUPPORTED; + } + + @Override + public int getLeMaximumAdvertisingDataLength() { + AdapterService service = getService(); + if (service == null) { + return 0; + } + + return service.getLeMaximumAdvertisingDataLength(); + } + + @Override + public boolean isActivityAndEnergyReportingSupported() { + AdapterService service = getService(); + if (service == null) { + return false; + } + + return service.getAdapterProperties().isActivityAndEnergyReportingSupported(); + } + + @Override + public BluetoothActivityEnergyInfo reportActivityInfo(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "reportActivityInfo")) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.reportActivityInfo(); + } + + @Override + public boolean registerMetadataListener( + IBluetoothMetadataListener listener, BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(listener); + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "registerMetadataListener") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "registerMetadataListener")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.getHandler() + .post( + () -> + service.getMetadataListeners() + .computeIfAbsent(device, k -> new RemoteCallbackList()) + .register(listener)); + return true; + } + + @Override + public boolean unregisterMetadataListener( + IBluetoothMetadataListener listener, BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(listener); + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "unregisterMetadataListener") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "unregisterMetadataListener")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.getHandler() + .post( + () -> + service.getMetadataListeners() + .computeIfPresent( + device, + (k, v) -> { + v.unregister(listener); + if (v.getRegisteredCallbackCount() == 0) { + return null; + } + return v; + })); + return true; + } + + @Override + public boolean setMetadata( + BluetoothDevice device, int key, byte[] value, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "setMetadata") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "setMetadata")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setMetadata(device, key, value); + } + + @Override + public byte[] getMetadata(BluetoothDevice device, int key, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getMetadata") + || !checkConnectPermissionForDataDelivery(service, source, TAG, "getMetadata")) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getMetadata(device, key); + } + + @Override + public int isRequestAudioPolicyAsSinkSupported( + BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser( + service, TAG, "isRequestAudioPolicyAsSinkSupported") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "isRequestAudioPolicyAsSinkSupported")) { + return BluetoothStatusCodes.FEATURE_NOT_CONFIGURED; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.isRequestAudioPolicyAsSinkSupported(device); + } + + @Override + public int requestAudioPolicyAsSink( + BluetoothDevice device, BluetoothSinkAudioPolicy policies, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } else if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "requestAudioPolicyAsSink")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } else if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "requestAudioPolicyAsSink")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.requestAudioPolicyAsSink(device, policies); + } + + @Override + public BluetoothSinkAudioPolicy getRequestedAudioPolicyAsSink( + BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser( + service, TAG, "getRequestedAudioPolicyAsSink") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "getRequestedAudioPolicyAsSink")) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getRequestedAudioPolicyAsSink(device); + } + + @Override + public void requestActivityInfo( + IBluetoothActivityEnergyInfoListener listener, AttributionSource source) { + BluetoothActivityEnergyInfo info = reportActivityInfo(source); + try { + listener.onBluetoothActivityEnergyInfoAvailable(info); + } catch (RemoteException e) { + Log.e(TAG, "onBluetoothActivityEnergyInfo: RemoteException", e); + } + } + + @Override + public void bleOnToOn(AttributionSource source) { + AdapterService service = getService(); + if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG, "bleOnToOn")) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.bleOnToOn(); + } + + @Override + public void bleOnToOff(AttributionSource source) { + AdapterService service = getService(); + if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG, "bleOnToOff")) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.bleOnToOff(); + } + + @Override + public void dump(FileDescriptor fd, String[] args) { + PrintWriter writer = new PrintWriter(new FileOutputStream(fd)); + AdapterService service = getService(); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(DUMP, null); + service.dump(fd, writer, args); + writer.close(); + } + + @Override + public boolean allowLowLatencyAudio(boolean allowed, BluetoothDevice device) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "allowLowLatencyAudio") + || !checkConnectPermissionForDataDelivery( + service, + Utils.getCallingAttributionSource(service), + TAG, + "allowLowLatencyAudio")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.allowLowLatencyAudio(allowed, device); + } + + @Override + public int startRfcommListener( + String name, ParcelUuid uuid, PendingIntent pendingIntent, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "startRfcommListener") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "startRfcommListener")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.startRfcommListener(name, uuid, pendingIntent, source); + } + + @Override + public int stopRfcommListener(ParcelUuid uuid, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser(service, TAG, "stopRfcommListener") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "stopRfcommListener")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.stopRfcommListener(uuid, source); + } + + @Override + public IncomingRfcommSocketInfo retrievePendingSocketForServiceRecord( + ParcelUuid uuid, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser( + service, TAG, "retrievePendingSocketForServiceRecord") + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "retrievePendingSocketForServiceRecord")) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.retrievePendingSocketForServiceRecord(uuid, source); + } + + @Override + public void setForegroundUserId(int userId, AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery( + service, + Utils.getCallingAttributionSource(mService), + TAG, + "setForegroundUserId")) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + Utils.setForegroundUserId(userId); + } + + @Override + public int setPreferredAudioProfiles( + BluetoothDevice device, Bundle modeToProfileBundle, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "setPreferredAudioProfiles")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + requireNonNull(device); + requireNonNull(modeToProfileBundle); + if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + if (service.getBondState(device) != BluetoothDevice.BOND_BONDED) { + return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED; + } + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "setPreferredAudioProfiles")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setPreferredAudioProfiles(device, modeToProfileBundle); + } + + @Override + public Bundle getPreferredAudioProfiles(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return Bundle.EMPTY; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "getPreferredAudioProfiles")) { + return Bundle.EMPTY; + } + requireNonNull(device); + if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + if (service.getBondState(device) != BluetoothDevice.BOND_BONDED) { + return Bundle.EMPTY; + } + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "getPreferredAudioProfiles")) { + return Bundle.EMPTY; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getPreferredAudioProfiles(device); + } + + @Override + public int notifyActiveDeviceChangeApplied(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystem(TAG, "notifyActiveDeviceChangeApplied")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + requireNonNull(device); + if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + if (service.getBondState(device) != BluetoothDevice.BOND_BONDED) { + return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED; + } + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "notifyActiveDeviceChangeApplied")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.notifyActiveDeviceChangeApplied(device); + } + + @Override + public int isDualModeAudioEnabled(AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "isDualModeAudioEnabled")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + if (!Utils.isDualModeAudioEnabled()) { + return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; + } + + return BluetoothStatusCodes.SUCCESS; + } + + @Override + public int registerPreferredAudioProfilesChangedCallback( + IBluetoothPreferredAudioProfilesCallback callback, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser( + service, TAG, "registerPreferredAudioProfilesChangedCallback")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + requireNonNull(callback); + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "registerPreferredAudioProfilesChangedCallback")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + // If LE only mode is enabled, the dual mode audio feature is disabled + if (!Utils.isDualModeAudioEnabled()) { + return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED; + } + + service.getPreferredAudioProfilesCallbacks().register(callback); + return BluetoothStatusCodes.SUCCESS; + } + + @Override + public int unregisterPreferredAudioProfilesChangedCallback( + IBluetoothPreferredAudioProfilesCallback callback, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser( + service, TAG, "unregisterPreferredAudioProfilesChangedCallback")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + requireNonNull(callback); + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "unregisterPreferredAudioProfilesChangedCallback")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + if (!service.getPreferredAudioProfilesCallbacks().unregister(callback)) { + Log.e( + TAG, + "unregisterPreferredAudioProfilesChangedCallback: callback was never " + + "registered"); + return BluetoothStatusCodes.ERROR_CALLBACK_NOT_REGISTERED; + } + return BluetoothStatusCodes.SUCCESS; + } + + @Override + public int registerBluetoothQualityReportReadyCallback( + IBluetoothQualityReportReadyCallback callback, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser( + service, TAG, "registerBluetoothQualityReportReadyCallback")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + requireNonNull(callback); + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "registerBluetoothQualityReportReadyCallback")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.getBluetoothQualityReportReadyCallbacks().register(callback); + return BluetoothStatusCodes.SUCCESS; + } + + @Override + public int unregisterBluetoothQualityReportReadyCallback( + IBluetoothQualityReportReadyCallback callback, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser( + service, TAG, "unregisterBluetoothQualityReportReadyCallback")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + requireNonNull(callback); + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "unregisterBluetoothQualityReportReadyCallback")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + if (!service.getBluetoothQualityReportReadyCallbacks().unregister(callback)) { + Log.e( + TAG, + "unregisterBluetoothQualityReportReadyCallback: callback was never registered"); + return BluetoothStatusCodes.ERROR_CALLBACK_NOT_REGISTERED; + } + return BluetoothStatusCodes.SUCCESS; + } + + @Override + public void registerHciVendorSpecificCallback( + IBluetoothHciVendorSpecificCallback callback, int[] eventCodes) { + AdapterService service = getService(); + if (service == null) { + return; + } + if (!callerIsSystemOrActiveOrManagedUser( + service, TAG, "registerHciVendorSpecificCallback")) { + throw new SecurityException("not allowed"); + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + requireNonNull(callback); + requireNonNull(eventCodes); + + Set<Integer> eventCodesSet = Arrays.stream(eventCodes).boxed().collect(Collectors.toSet()); + if (eventCodesSet.stream() + .anyMatch((n) -> (n < 0) || (n >= 0x52 && n < 0x60) || (n > 0xff))) { + throw new IllegalArgumentException("invalid vendor-specific event code"); + } + + service.getBluetoothHciVendorSpecificDispatcher().register(callback, eventCodesSet); + } + + @Override + public void unregisterHciVendorSpecificCallback(IBluetoothHciVendorSpecificCallback callback) { + AdapterService service = getService(); + if (service == null) { + return; + } + if (!callerIsSystemOrActiveOrManagedUser( + service, TAG, "unregisterHciVendorSpecificCallback")) { + throw new SecurityException("not allowed"); + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + requireNonNull(callback); + service.getBluetoothHciVendorSpecificDispatcher().unregister(callback); + } + + @Override + public void sendHciVendorSpecificCommand( + int ocf, byte[] parameters, IBluetoothHciVendorSpecificCallback callback) { + AdapterService service = getService(); + if (service == null) { + return; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "sendHciVendorSpecificCommand")) { + throw new SecurityException("not allowed"); + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + // Open this no-op android command for test purpose + int getVendorCapabilitiesOcf = 0x153; + if (ocf < 0 + || (ocf >= 0x150 && ocf < 0x160 && ocf != getVendorCapabilitiesOcf) + || (ocf > 0x3ff)) { + throw new IllegalArgumentException("invalid vendor-specific event code"); + } + requireNonNull(parameters); + if (parameters.length > 255) { + throw new IllegalArgumentException("Parameters size is too big"); + } + + Optional<byte[]> cookie = + service.getBluetoothHciVendorSpecificDispatcher().getRegisteredCookie(callback); + if (!cookie.isPresent()) { + Log.e(TAG, "send command without registered callback"); + throw new IllegalStateException("callback not registered"); + } + + service.getBluetoothHciVendorSpecificNativeInterface() + .sendCommand(ocf, parameters, cookie.get()); + } + + @Override + public int getOffloadedTransportDiscoveryDataScanSupported(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !callerIsSystemOrActiveOrManagedUser( + service, TAG, "getOffloadedTransportDiscoveryDataScanSupported") + || !checkScanPermissionForDataDelivery( + service, source, TAG, "getOffloadedTransportDiscoveryDataScanSupported")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getOffloadedTransportDiscoveryDataScanSupported(); + } + + @Override + public boolean isMediaProfileConnected(AttributionSource source) { + AdapterService service = getService(); + if (service == null + || !checkConnectPermissionForDataDelivery( + service, source, TAG, "isMediaProfileConnected")) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.isMediaProfileConnected(); + } + + @Override + public IBinder getBluetoothGatt() { + AdapterService service = getService(); + return service == null ? null : service.getBluetoothGatt(); + } + + @Override + public IBinder getBluetoothScan() { + AdapterService service = getService(); + return service == null ? null : service.getBluetoothScan(); + } + + @Override + public void unregAllGattClient(AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.unregAllGattClient(source); + } + + @Override + public IBinder getProfile(int profileId) { + AdapterService service = getService(); + if (service == null) { + return null; + } + + return service.getProfile(profileId); + } + + @Override + public int setActiveAudioDevicePolicy( + BluetoothDevice device, int activeAudioDevicePolicy, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "setActiveAudioDevicePolicy")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "setActiveAudioDevicePolicy")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getDatabaseManager() + .setActiveAudioDevicePolicy(device, activeAudioDevicePolicy); + } + + @Override + public int getActiveAudioDevicePolicy(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return BluetoothDevice.ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "getActiveAudioDevicePolicy")) { + throw new IllegalStateException( + "Caller is not the system or part of the active/managed user"); + } + if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "getActiveAudioDevicePolicy")) { + return BluetoothDevice.ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getDatabaseManager().getActiveAudioDevicePolicy(device); + } + + @Override + public int setMicrophonePreferredForCalls( + BluetoothDevice device, boolean enabled, AttributionSource source) { + requireNonNull(device); + AdapterService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "setMicrophonePreferredForCalls")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "setMicrophonePreferredForCalls")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getDatabaseManager().setMicrophonePreferredForCalls(device, enabled); + } + + @Override + public boolean isMicrophonePreferredForCalls(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + AdapterService service = getService(); + if (service == null) { + return true; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "isMicrophonePreferredForCalls")) { + throw new IllegalStateException( + "Caller is not the system or part of the active/managed user"); + } + if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + if (!checkConnectPermissionForDataDelivery( + service, source, TAG, "isMicrophonePreferredForCalls")) { + return true; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getDatabaseManager().isMicrophonePreferredForCalls(device); + } + + @Override + public boolean isLeCocSocketOffloadSupported(AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return false; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.isLeCocSocketOffloadSupported(); + } + + @Override + public boolean isRfcommSocketOffloadSupported(AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return false; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.isRfcommSocketOffloadSupported(); + } + + @Override + public IBinder getBluetoothAdvertise() { + AdapterService service = getService(); + return service == null ? null : service.getBluetoothAdvertise(); + } + + @Override + public IBinder getDistanceMeasurement() { + AdapterService service = getService(); + return service == null ? null : service.getDistanceMeasurement(); + } + + @Override + public int getKeyMissingCount(BluetoothDevice device, AttributionSource source) { + AdapterService service = getService(); + if (service == null) { + return -1; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "getKeyMissingCount")) { + throw new IllegalStateException( + "Caller is not the system or part of the active/managed user"); + } + if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + if (!checkConnectPermissionForDataDelivery(service, source, TAG, "getKeyMissingCount")) { + return -1; + } + + return service.getDatabaseManager().getKeyMissingCount(device); + } +} diff --git a/android/app/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java b/android/app/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java index c9b1c82473..0bdebd30e5 100644 --- a/android/app/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java +++ b/android/app/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java @@ -29,7 +29,6 @@ import android.os.ParcelUuid; import android.util.Log; import com.android.bluetooth.Utils; -import com.android.bluetooth.flags.Flags; class BluetoothSocketManagerBinder extends IBluetoothSocketManager.Stub { private static final String TAG = BluetoothSocketManagerBinder.class.getSimpleName(); @@ -58,10 +57,7 @@ class BluetoothSocketManagerBinder extends IBluetoothSocketManager.Stub { return null; } - String brEdrAddress = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(device) - : mService.getIdentityAddress(device.getAddress()); + String brEdrAddress = Utils.getBrEdrAddress(device); Log.i( TAG, @@ -118,10 +114,7 @@ class BluetoothSocketManagerBinder extends IBluetoothSocketManager.Stub { mService.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); enforceSocketOffloadSupport(type); } - String brEdrAddress = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(device) - : mService.getIdentityAddress(device.getAddress()); + String brEdrAddress = Utils.getBrEdrAddress(device); Log.i( TAG, @@ -286,7 +279,7 @@ class BluetoothSocketManagerBinder extends IBluetoothSocketManager.Stub { || !Utils.callerIsSystemOrActiveOrManagedUser( service, TAG, "getL2capLocalChannelId") || !Utils.checkConnectPermissionForDataDelivery( - service, source, "BluetoothSocketManagerBinder getL2capLocalChannelId")) { + service, source, TAG, "getL2capLocalChannelId")) { return INVALID_CID; } service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); @@ -300,7 +293,7 @@ class BluetoothSocketManagerBinder extends IBluetoothSocketManager.Stub { || !Utils.callerIsSystemOrActiveOrManagedUser( service, TAG, "getL2capRemoteChannelId") || !Utils.checkConnectPermissionForDataDelivery( - service, source, "BluetoothSocketManagerBinder getL2capRemoteChannelId")) { + service, source, TAG, "getL2capRemoteChannelId")) { return INVALID_CID; } service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); diff --git a/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java b/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java index 644b52dc8a..f59e69a42d 100644 --- a/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java +++ b/android/app/src/com/android/bluetooth/btservice/MetricsLogger.java @@ -37,6 +37,12 @@ import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVEN import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__EVENT_TYPE__PROFILE_CONNECTION_VOLUME_CONTROL; import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__STATE_BONDED; import static com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__STATE_NONE; +import static com.android.bluetooth.BluetoothStatsLog.HEARING_DEVICE_ACTIVE_EVENT_REPORTED__DEVICE_TYPE__ASHA; +import static com.android.bluetooth.BluetoothStatsLog.HEARING_DEVICE_ACTIVE_EVENT_REPORTED__DEVICE_TYPE__CLASSIC; +import static com.android.bluetooth.BluetoothStatsLog.HEARING_DEVICE_ACTIVE_EVENT_REPORTED__DEVICE_TYPE__LE_AUDIO; +import static com.android.bluetooth.BluetoothStatsLog.HEARING_DEVICE_ACTIVE_EVENT_REPORTED__TIME_PERIOD__DAY; +import static com.android.bluetooth.BluetoothStatsLog.HEARING_DEVICE_ACTIVE_EVENT_REPORTED__TIME_PERIOD__MONTH; +import static com.android.bluetooth.BluetoothStatsLog.HEARING_DEVICE_ACTIVE_EVENT_REPORTED__TIME_PERIOD__WEEK; import static com.android.bluetooth.BtRestrictedStatsLog.RESTRICTED_BLUETOOTH_DEVICE_NAME_REPORTED; import android.app.AlarmManager; @@ -45,6 +51,7 @@ import android.bluetooth.BluetoothA2dpSink; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAvrcpController; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHapClient; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothHearingAid; @@ -60,11 +67,13 @@ import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProtoEnums; import android.bluetooth.BluetoothSap; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Build; import android.os.SystemClock; +import android.provider.Settings; import android.util.Log; import android.util.proto.ProtoOutputStream; @@ -87,11 +96,14 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.function.BiPredicate; /** Class of Bluetooth Metrics */ public class MetricsLogger { @@ -273,6 +285,7 @@ public class MetricsLogger { filter.addAction(BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothSap.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED); mAdapterService.registerReceiver(mReceiver, filter); } @@ -285,9 +298,18 @@ public class MetricsLogger { Log.w(TAG, "Received intent with null action"); return; } + BluetoothDevice device = + intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); switch (action) { case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED: logConnectionStateChanges(BluetoothProfile.A2DP, intent); + if (state == BluetoothProfile.STATE_CONNECTED + && isMedicalDevice(device)) { + updateHearingDeviceActiveTime( + device, + HEARING_DEVICE_ACTIVE_EVENT_REPORTED__DEVICE_TYPE__CLASSIC); + } break; case BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED: logConnectionStateChanges(BluetoothProfile.A2DP_SINK, intent); @@ -297,12 +319,23 @@ public class MetricsLogger { break; case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED: logConnectionStateChanges(BluetoothProfile.HEADSET, intent); + if (state == BluetoothProfile.STATE_CONNECTED + && isMedicalDevice(device)) { + updateHearingDeviceActiveTime( + device, + HEARING_DEVICE_ACTIVE_EVENT_REPORTED__DEVICE_TYPE__CLASSIC); + } break; case BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED: logConnectionStateChanges(BluetoothProfile.HEADSET_CLIENT, intent); break; case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED: logConnectionStateChanges(BluetoothProfile.HEARING_AID, intent); + if (state == BluetoothProfile.STATE_CONNECTED) { + updateHearingDeviceActiveTime( + device, + HEARING_DEVICE_ACTIVE_EVENT_REPORTED__DEVICE_TYPE__ASHA); + } break; case BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED: logConnectionStateChanges(BluetoothProfile.HID_DEVICE, intent); @@ -331,6 +364,14 @@ public class MetricsLogger { case BluetoothSap.ACTION_CONNECTION_STATE_CHANGED: logConnectionStateChanges(BluetoothProfile.SAP, intent); break; + case BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED: + if (state == BluetoothProfile.STATE_CONNECTED) { + updateHearingDeviceActiveTime( + device, + HEARING_DEVICE_ACTIVE_EVENT_REPORTED__DEVICE_TYPE__LE_AUDIO + ); + } + break; default: Log.w(TAG, "Received unknown intent " + intent); break; @@ -646,7 +687,8 @@ public class MetricsLogger { int numOngoingScan, boolean isScreenOn, boolean isAppDead, - int appImportance) { + int appImportance, + String attributionTag) { BluetoothStatsLog.write( BluetoothStatsLog.LE_APP_SCAN_STATE_CHANGED, uids, @@ -662,7 +704,8 @@ public class MetricsLogger { numOngoingScan, isScreenOn, isAppDead, - convertAppImportance(appImportance)); + convertAppImportance(appImportance), + attributionTag); } /** Logs the radio scan stats with app attribution when the radio scan stopped. */ @@ -675,7 +718,8 @@ public class MetricsLogger { long scanWindowMillis, boolean isScreenOn, long scanDurationMillis, - int appImportance) { + int appImportance, + String attributionTag) { BluetoothStatsLog.write( BluetoothStatsLog.LE_RADIO_SCAN_STOPPED, uids, @@ -686,7 +730,8 @@ public class MetricsLogger { scanWindowMillis, isScreenOn, scanDurationMillis, - convertAppImportance(appImportance)); + convertAppImportance(appImportance), + attributionTag); } /** Logs the advertise stats with app attribution when the advertise state changed. */ @@ -702,7 +747,8 @@ public class MetricsLogger { boolean isExtendedAdv, int instanceCount, long advDurationMs, - int appImportance) { + int appImportance, + String attributionTag) { BluetoothStatsLog.write( BluetoothStatsLog.LE_ADV_STATE_CHANGED, uids, @@ -716,7 +762,8 @@ public class MetricsLogger { isExtendedAdv, instanceCount, advDurationMs, - convertAppImportance(appImportance)); + convertAppImportance(appImportance), + attributionTag); } protected String getAllowlistedDeviceNameHash( @@ -909,4 +956,56 @@ public class MetricsLogger { syncStatus, getRemoteDeviceInfoProto(device, false)); } + + void logHearingDeviceActiveEvent(BluetoothDevice device, int type, int timePeriod) { + BluetoothStatsLog.write( + BluetoothStatsLog.HEARING_DEVICE_ACTIVE_EVENT_REPORTED, + type, + timePeriod, + getRemoteDeviceInfoProto(device, true)); + } + + void updateHearingDeviceActiveTime(BluetoothDevice device, int deviceTypeProto) { + // Time comparison includes a +/- 1 hour tolerance to prevent data loss + updateLastActiveTime( + device, + deviceTypeProto, + HEARING_DEVICE_ACTIVE_EVENT_REPORTED__TIME_PERIOD__DAY, + "last_active_day", + (now, lastActive) -> now.isAfter(lastActive.plusDays(1).minusHours(1))); + updateLastActiveTime( + device, + deviceTypeProto, + HEARING_DEVICE_ACTIVE_EVENT_REPORTED__TIME_PERIOD__WEEK, + "last_active_week", + (now, lastActive) -> now.isAfter(lastActive.plusWeeks(1).minusHours(1))); + updateLastActiveTime( + device, + deviceTypeProto, + HEARING_DEVICE_ACTIVE_EVENT_REPORTED__TIME_PERIOD__MONTH, + "last_active_month", + (now, lastActive) -> now.isAfter(lastActive.plusMonths(1).minusHours(1))); + } + + private void updateLastActiveTime( + BluetoothDevice device, + int deviceTypeProto, + int timePeriodProto, + String timePeriodSettingsKey, + BiPredicate<LocalDateTime, LocalDateTime> timeComparison) { + final ContentResolver contentResolver = mAdapterService.getContentResolver(); + final String lastActive = Settings.Secure.getString(contentResolver, timePeriodSettingsKey); + final LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault()); + if (lastActive == null || timeComparison.test(now, LocalDateTime.parse(lastActive))) { + Settings.Secure.putString(contentResolver, timePeriodSettingsKey, now.toString()); + logHearingDeviceActiveEvent(device, deviceTypeProto, timePeriodProto); + } + } + + private boolean isMedicalDevice(BluetoothDevice device) { + final String deviceName = mAdapterService.getRemoteName(device); + final List<String> wordBreakdownList = getWordBreakdownList(deviceName); + boolean isMedicalDevice = !getMatchedStringForMedicalDevice(wordBreakdownList).isEmpty(); + return isMedicalDevice; + } } diff --git a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java index 456545a42a..c49659863b 100644 --- a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java +++ b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java @@ -27,6 +27,7 @@ import static com.android.modules.utils.build.SdkLevel.isAtLeastV; import static java.util.Objects.requireNonNullElseGet; +import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.app.Activity; @@ -43,8 +44,11 @@ import android.bluetooth.BluetoothProtoEnums; import android.bluetooth.BluetoothSinkAudioPolicy; import android.bluetooth.BluetoothUtils; import android.bluetooth.IBluetoothConnectionCallback; +import android.content.AttributionSource; import android.content.Intent; +import android.content.pm.Attribution; import android.net.MacAddress; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -64,9 +68,13 @@ import com.android.modules.utils.build.SdkLevel; import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Predicate; @@ -329,6 +337,7 @@ public class RemoteDevices { } class DeviceProperties { + private static final int MAX_PACKAGE_NAMES = 4; private String mName; private byte[] mAddress; private String mIdentityAddress; @@ -354,6 +363,16 @@ public class RemoteDevices { @VisibleForTesting boolean mHfpBatteryIndicator = false; private BluetoothSinkAudioPolicy mAudioPolicy; + // LRU cache of package names associated to this device + private final Set<String> mPackages = + Collections.newSetFromMap( + new LinkedHashMap<String, Boolean>() { + // This is called on every add. Returning true removes the eldest entry. + protected boolean removeEldestEntry(Map.Entry<String, Boolean> eldest) { + return size() >= MAX_PACKAGE_NAMES; + } + }); + DeviceProperties() { mBondState = BluetoothDevice.BOND_NONE; } @@ -858,6 +877,22 @@ public class RemoteDevices { return mModelName; } } + + @NonNull + public String[] getPackages() { + synchronized (mObject) { + return mPackages.toArray(new String[0]); + } + } + + public void addPackage(String packageName) { + synchronized (mObject) { + // Removing the package ensures that the LRU cache order is updated. Adding it back + // will make it the newest. + mPackages.remove(packageName); + mPackages.add(packageName); + } + } } private void sendUuidIntent(BluetoothDevice device, DeviceProperties prop, boolean success) { @@ -1574,6 +1609,28 @@ public class RemoteDevices { // Bond loss detected, add to the count. mAdapterService.getDatabase().updateKeyMissingCount(bluetoothDevice, true); + // Some apps are not able to handle the key missing broadcast, so we need to remove + // the bond to prevent them from misbehaving. + // TODO (b/402854328): Remove when the misbehaving apps are updated + if (bondLossIopFixNeeded(bluetoothDevice)) { + DeviceProperties deviceProperties = getDeviceProperties(bluetoothDevice); + if (deviceProperties == null) { + return; + } + String[] packages = deviceProperties.getPackages(); + if (packages.length == 0) { + return; + } + + Log.w( + TAG, + "Removing " + + bluetoothDevice + + " on behalf of: " + + Arrays.toString(packages)); + bluetoothDevice.removeBond(); + } + if (Flags.keyMissingPublic()) { mAdapterService.sendOrderedBroadcast( intent, @@ -1992,6 +2049,55 @@ public class RemoteDevices { device, batteryChargeIndicatorToPercentage(batteryLevel), /* isBas= */ false); } + private static final String[] BOND_LOSS_IOP_PACKAGES = { + "com.sjm.crmd.patientApp_Android", "com.abbott.crm.ngq.patient", + }; + + private static final Set<String> BOND_LOSS_IOP_DEVICE_NAMES = Set.of("CM", "DM"); + + // TODO (b/402854328): Remove when the misbehaving apps are updated + public boolean bondLossIopFixNeeded(BluetoothDevice device) { + DeviceProperties deviceProperties = getDeviceProperties(device); + if (deviceProperties == null) { + return false; + } + + String deviceName = deviceProperties.getName(); + if (deviceName == null) { + return false; + } + + String[] packages = deviceProperties.getPackages(); + if (packages.length == 0) { + return false; + } + + if (!BOND_LOSS_IOP_DEVICE_NAMES.contains(deviceName)) { + return false; + } + + for (String iopFixPackage : BOND_LOSS_IOP_PACKAGES) { + for (String packageName : packages) { + if (packageName.contains(iopFixPackage) + && !Utils.checkCallerTargetSdk( + mAdapterService, packageName, Build.VERSION_CODES.BAKLAVA)) { + Log.w( + TAG, + "bondLossIopFixNeeded(): " + + " IOP fix needed for " + + device + + " name: " + + deviceName + + " package: " + + packageName); + return true; + } + } + } + + return false; + } + private static void errorLog(String msg) { Log.e(TAG, msg); } diff --git a/android/app/src/com/android/bluetooth/btservice/SilenceDeviceManager.java b/android/app/src/com/android/bluetooth/btservice/SilenceDeviceManager.java index 4acfefc0d8..90d9a4bee6 100644 --- a/android/app/src/com/android/bluetooth/btservice/SilenceDeviceManager.java +++ b/android/app/src/com/android/bluetooth/btservice/SilenceDeviceManager.java @@ -31,7 +31,6 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.a2dp.A2dpService; import com.android.bluetooth.hfp.HeadsetService; -import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.HashMap; @@ -205,7 +204,6 @@ public class SilenceDeviceManager { mSilenceDevices.clear(); } - @VisibleForTesting boolean setSilenceMode(BluetoothDevice device, boolean silence) { Log.d(TAG, "setSilenceMode: " + device + ", " + silence); mHandler.obtainMessage( diff --git a/android/app/src/com/android/bluetooth/content_profiles/OWNERS b/android/app/src/com/android/bluetooth/content_profiles/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/src/com/android/bluetooth/content_profiles/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java index 2b49f467a8..7a6597f5b0 100644 --- a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java +++ b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java @@ -17,7 +17,6 @@ package com.android.bluetooth.csip; -import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; @@ -31,7 +30,6 @@ import static java.util.Objects.requireNonNullElseGet; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.RequiresPermission; import android.bluetooth.BluetoothCsipSetCoordinator; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; @@ -40,7 +38,6 @@ import android.bluetooth.BluetoothUuid; import android.bluetooth.IBluetoothCsipSetCoordinator; import android.bluetooth.IBluetoothCsipSetCoordinatorCallback; import android.bluetooth.IBluetoothCsipSetCoordinatorLockCallback; -import android.content.AttributionSource; import android.content.Intent; import android.os.Handler; import android.os.HandlerThread; @@ -152,7 +149,7 @@ public class CsipSetCoordinatorService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new BluetoothCsisBinder(this); + return new CsipSetCoordinatorServiceBinder(this); } @Override @@ -991,171 +988,6 @@ public class CsipSetCoordinatorService extends ProfileService { BluetoothProfile.CSIP_SET_COORDINATOR, device, fromState, toState); } - /** Binder object: must be a static class or memory leak may occur */ - @VisibleForTesting - static class BluetoothCsisBinder extends IBluetoothCsipSetCoordinator.Stub - implements IProfileServiceBinder { - private CsipSetCoordinatorService mService; - - BluetoothCsisBinder(CsipSetCoordinatorService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) - private CsipSetCoordinatorService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - CsipSetCoordinatorService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service; - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - requireNonNull(source); - - CsipSetCoordinatorService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - requireNonNull(source); - - CsipSetCoordinatorService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - CsipSetCoordinatorService service = getService(source); - if (service == null) { - return STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - CsipSetCoordinatorService service = getService(source); - if (service == null) { - return false; - } - - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - CsipSetCoordinatorService service = getService(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - return service.getConnectionPolicy(device); - } - - @Override - public ParcelUuid lockGroup( - int groupId, - @NonNull IBluetoothCsipSetCoordinatorLockCallback callback, - AttributionSource source) { - requireNonNull(callback); - requireNonNull(source); - - CsipSetCoordinatorService service = getService(source); - if (service == null) { - return null; - } - - UUID lockUuid = service.lockGroup(groupId, callback); - return lockUuid == null ? null : new ParcelUuid(lockUuid); - } - - @Override - public void unlockGroup(@NonNull ParcelUuid lockUuid, AttributionSource source) { - requireNonNull(lockUuid); - requireNonNull(source); - - CsipSetCoordinatorService service = getService(source); - if (service == null) { - return; - } - - service.unlockGroup(lockUuid.getUuid()); - } - - @Override - public List<Integer> getAllGroupIds(ParcelUuid uuid, AttributionSource source) { - requireNonNull(uuid); - requireNonNull(source); - - CsipSetCoordinatorService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getAllGroupIds(uuid); - } - - @Override - public Map<Integer, ParcelUuid> getGroupUuidMapByDevice( - BluetoothDevice device, AttributionSource source) { - CsipSetCoordinatorService service = getService(source); - if (service == null) { - return null; - } - - return service.getGroupUuidMapByDevice(device); - } - - @Override - public int getDesiredGroupSize(int groupId, AttributionSource source) { - CsipSetCoordinatorService service = getService(source); - if (service == null) { - return IBluetoothCsipSetCoordinator.CSIS_GROUP_SIZE_UNKNOWN; - } - - return service.getDesiredGroupSize(groupId); - } - } - @Override public void dump(StringBuilder sb) { super.dump(sb); diff --git a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceBinder.java b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceBinder.java new file mode 100644 index 0000000000..5b08c1983b --- /dev/null +++ b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceBinder.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.csip; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IBluetoothCsipSetCoordinator; +import android.bluetooth.IBluetoothCsipSetCoordinatorLockCallback; +import android.content.AttributionSource; +import android.os.ParcelUuid; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +class CsipSetCoordinatorServiceBinder extends IBluetoothCsipSetCoordinator.Stub + implements IProfileServiceBinder { + private static final String TAG = CsipSetCoordinatorServiceBinder.class.getSimpleName(); + + private CsipSetCoordinatorService mService; + + CsipSetCoordinatorServiceBinder(CsipSetCoordinatorService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) + private CsipSetCoordinatorService getService(AttributionSource source) { + CsipSetCoordinatorService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service; + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + requireNonNull(source); + + CsipSetCoordinatorService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + requireNonNull(source); + + CsipSetCoordinatorService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + CsipSetCoordinatorService service = getService(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + CsipSetCoordinatorService service = getService(source); + if (service == null) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + CsipSetCoordinatorService service = getService(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + return service.getConnectionPolicy(device); + } + + @Override + public ParcelUuid lockGroup( + int groupId, + @NonNull IBluetoothCsipSetCoordinatorLockCallback callback, + AttributionSource source) { + requireNonNull(callback); + requireNonNull(source); + + CsipSetCoordinatorService service = getService(source); + if (service == null) { + return null; + } + + UUID lockUuid = service.lockGroup(groupId, callback); + return lockUuid == null ? null : new ParcelUuid(lockUuid); + } + + @Override + public void unlockGroup(@NonNull ParcelUuid lockUuid, AttributionSource source) { + requireNonNull(lockUuid); + requireNonNull(source); + + CsipSetCoordinatorService service = getService(source); + if (service == null) { + return; + } + service.unlockGroup(lockUuid.getUuid()); + } + + @Override + public List<Integer> getAllGroupIds(ParcelUuid uuid, AttributionSource source) { + requireNonNull(uuid); + requireNonNull(source); + + CsipSetCoordinatorService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getAllGroupIds(uuid); + } + + @Override + public Map<Integer, ParcelUuid> getGroupUuidMapByDevice( + BluetoothDevice device, AttributionSource source) { + CsipSetCoordinatorService service = getService(source); + if (service == null) { + return null; + } + return service.getGroupUuidMapByDevice(device); + } + + @Override + public int getDesiredGroupSize(int groupId, AttributionSource source) { + CsipSetCoordinatorService service = getService(source); + if (service == null) { + return IBluetoothCsipSetCoordinator.CSIS_GROUP_SIZE_UNKNOWN; + } + return service.getDesiredGroupSize(groupId); + } +} diff --git a/android/app/src/com/android/bluetooth/csip/OWNERS b/android/app/src/com/android/bluetooth/csip/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/app/src/com/android/bluetooth/csip/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/app/src/com/android/bluetooth/gatt/AppAdvertiseStats.java b/android/app/src/com/android/bluetooth/gatt/AppAdvertiseStats.java index b9ebfad69f..44154b31bd 100644 --- a/android/app/src/com/android/bluetooth/gatt/AppAdvertiseStats.java +++ b/android/app/src/com/android/bluetooth/gatt/AppAdvertiseStats.java @@ -35,7 +35,6 @@ import androidx.annotation.VisibleForTesting; import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.btservice.MetricsLogger; -import com.android.bluetooth.flags.Flags; import java.time.Duration; import java.time.Instant; @@ -219,14 +218,13 @@ class AppAdvertiseStats { } void recordAdvertiseErrorCount(int status) { - if (Flags.bleScanAdvMetricsRedesign()) { - BluetoothStatsLog.write( - BluetoothStatsLog.LE_ADV_ERROR_REPORTED, - new int[] {mAppUid}, - new String[] {mAppName}, - BluetoothStatsLog.LE_ADV_ERROR_REPORTED__LE_ADV_OP_CODE__ERROR_CODE_ON_START, - convertStatusCode(status)); - } + BluetoothStatsLog.write( + BluetoothStatsLog.LE_ADV_ERROR_REPORTED, + new int[] {mAppUid}, + new String[] {mAppName}, + BluetoothStatsLog.LE_ADV_ERROR_REPORTED__LE_ADV_OP_CODE__ERROR_CODE_ON_START, + convertStatusCode(status), + getAttributionTag()); MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.LE_ADV_ERROR_ON_START_COUNT, 1); } @@ -355,6 +353,10 @@ class AppAdvertiseStats { mAppImportance = importance; } + private String getAttributionTag() { + return mAttributionTag != null ? mAttributionTag : ""; + } + private static void recordAdvertiseDurationCount( Duration duration, boolean isConnectable, boolean inPeriodic) { if (duration.compareTo(Duration.ofMinutes(1)) < 0) { @@ -416,22 +418,21 @@ class AppAdvertiseStats { } private void recordAdvertiseEnableCount(boolean enable, int instanceCount, long durationMs) { - if (Flags.bleScanAdvMetricsRedesign()) { - MetricsLogger.getInstance() - .logAdvStateChanged( - new int[] {mAppUid}, - new String[] {mAppName}, - enable /* enabled */, - convertAdvInterval(mInterval), - convertTxPowerLevel(mTxPowerLevel), - mConnectable, - mPeriodicAdvertisingEnabled, - mScanResponseData != null && mScannable /* hasScanResponse */, - !mLegacy /* isExtendedAdv */, - instanceCount, - durationMs, - mAppImportance); - } + MetricsLogger.getInstance() + .logAdvStateChanged( + new int[] {mAppUid}, + new String[] {mAppName}, + enable /* enabled */, + convertAdvInterval(mInterval), + convertTxPowerLevel(mTxPowerLevel), + mConnectable, + mPeriodicAdvertisingEnabled, + mScanResponseData != null && mScannable /* hasScanResponse */, + !mLegacy /* isExtendedAdv */, + instanceCount, + durationMs, + mAppImportance, + getAttributionTag()); if (enable) { MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.LE_ADV_COUNT_ENABLE, 1); if (mConnectable) { diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java index aaa00b45df..10190b09ef 100644 --- a/android/app/src/com/android/bluetooth/gatt/GattService.java +++ b/android/app/src/com/android/bluetooth/gatt/GattService.java @@ -24,8 +24,8 @@ import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; import static android.bluetooth.BluetoothUtils.toAnonymizedAddress; import static com.android.bluetooth.Utils.callbackToApp; -import static com.android.bluetooth.Utils.callerIsSystemOrActiveOrManagedUser; import static com.android.bluetooth.Utils.checkCallerTargetSdk; +import static com.android.bluetooth.Utils.checkConnectPermissionForDataDelivery; import static com.android.bluetooth.util.AttributionSourceUtil.getLastAttributionTag; import static java.util.Objects.requireNonNull; @@ -43,7 +43,6 @@ import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProtoEnums; import android.bluetooth.BluetoothStatusCodes; -import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothGattCallback; import android.bluetooth.IBluetoothGattServerCallback; import android.companion.CompanionDeviceManager; @@ -212,7 +211,7 @@ public class GattService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new BluetoothGattBinder(this); + return new GattServiceBinder(this); } @Override @@ -263,6 +262,10 @@ public class GattService extends ProfileService { return mScanController; } + CompanionDeviceManager getCompanionDeviceManager() { + return mCompanionDeviceManager; + } + @Override protected void setTestModeEnabled(boolean enableTestMode) { if (mScanController != null) { @@ -330,479 +333,6 @@ public class GattService extends ProfileService { } } - /** Handlers for incoming service calls */ - @VisibleForTesting - static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder { - private GattService mService; - - BluetoothGattBinder(GattService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - private GattService getService() { - // Cache mService because it can change while getService is called - GattService service = mService; - - if (service == null || !service.isAvailable()) { - Log.e(TAG, "getService() - Service requested, but not available!"); - return null; - } - - return service; - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return Collections.emptyList(); - } - return service.getDevicesMatchingConnectionStates(states, source); - } - - @Override - public void registerClient( - ParcelUuid uuid, - IBluetoothGattCallback callback, - boolean eattSupport, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.registerClient(uuid.getUuid(), callback, eattSupport, source); - } - - @Override - public void unregisterClient(int clientIf, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.unregisterClient( - clientIf, source, ContextMap.RemoveReason.REASON_UNREGISTER_CLIENT); - } - - @Override - public void clientConnect( - int clientIf, - String address, - int addressType, - boolean isDirect, - int transport, - boolean opportunistic, - int phy, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.clientConnect( - clientIf, - address, - addressType, - isDirect, - transport, - opportunistic, - phy, - source); - } - - @Override - public void clientDisconnect(int clientIf, String address, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.clientDisconnect(clientIf, address, source); - } - - @Override - public void clientSetPreferredPhy( - int clientIf, - String address, - int txPhy, - int rxPhy, - int phyOptions, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.clientSetPreferredPhy(clientIf, address, txPhy, rxPhy, phyOptions, source); - } - - @Override - public void clientReadPhy(int clientIf, String address, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.clientReadPhy(clientIf, address, source); - } - - @Override - public void refreshDevice(int clientIf, String address, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.refreshDevice(clientIf, address, source); - } - - @Override - public void discoverServices(int clientIf, String address, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.discoverServices(clientIf, address, source); - } - - @Override - public void discoverServiceByUuid( - int clientIf, String address, ParcelUuid uuid, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.discoverServiceByUuid(clientIf, address, uuid.getUuid(), source); - } - - @Override - public void readCharacteristic( - int clientIf, String address, int handle, int authReq, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.readCharacteristic(clientIf, address, handle, authReq, source); - } - - @Override - public void readUsingCharacteristicUuid( - int clientIf, - String address, - ParcelUuid uuid, - int startHandle, - int endHandle, - int authReq, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.readUsingCharacteristicUuid( - clientIf, address, uuid.getUuid(), startHandle, endHandle, authReq, source); - } - - @Override - public int writeCharacteristic( - int clientIf, - String address, - int handle, - int writeType, - int authReq, - byte[] value, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } - return service.writeCharacteristic( - clientIf, address, handle, writeType, authReq, value, source); - } - - @Override - public void readDescriptor( - int clientIf, String address, int handle, int authReq, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.readDescriptor(clientIf, address, handle, authReq, source); - } - - @Override - public int writeDescriptor( - int clientIf, - String address, - int handle, - int authReq, - byte[] value, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } - return service.writeDescriptor(clientIf, address, handle, authReq, value, source); - } - - @Override - public void beginReliableWrite(int clientIf, String address, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.beginReliableWrite(clientIf, address, source); - } - - @Override - public void endReliableWrite( - int clientIf, String address, boolean execute, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.endReliableWrite(clientIf, address, execute, source); - } - - @Override - public void registerForNotification( - int clientIf, - String address, - int handle, - boolean enable, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.registerForNotification(clientIf, address, handle, enable, source); - } - - @Override - public void readRemoteRssi(int clientIf, String address, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.readRemoteRssi(clientIf, address, source); - } - - @Override - public void configureMTU(int clientIf, String address, int mtu, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.configureMTU(clientIf, address, mtu, source); - } - - @Override - public void connectionParameterUpdate( - int clientIf, String address, int connectionPriority, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.connectionParameterUpdate(clientIf, address, connectionPriority, source); - } - - @Override - public void leConnectionUpdate( - int clientIf, - String address, - int minConnectionInterval, - int maxConnectionInterval, - int peripheralLatency, - int supervisionTimeout, - int minConnectionEventLen, - int maxConnectionEventLen, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.leConnectionUpdate( - clientIf, - address, - minConnectionInterval, - maxConnectionInterval, - peripheralLatency, - supervisionTimeout, - minConnectionEventLen, - maxConnectionEventLen, - source); - } - - @Override - public int subrateModeRequest( - int clientIf, BluetoothDevice device, int subrateMode, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; - } - if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "subrateModeRequest")) { - return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; - } - - if (!Utils.checkConnectPermissionForDataDelivery( - service, source, "GattService subrateModeRequest")) { - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; - } - - Utils.enforceCdmAssociationIfNotBluetoothPrivileged( - service, service.mCompanionDeviceManager, source, device); - - if (subrateMode < BluetoothGatt.SUBRATE_REQUEST_MODE_BALANCED - || subrateMode > BluetoothGatt.SUBRATE_REQUEST_MODE_LOW_POWER) { - throw new IllegalArgumentException("Subrate Mode not within valid range"); - } - - requireNonNull(device); - String address = device.getAddress(); - if (!BluetoothAdapter.checkBluetoothAddress(address)) { - throw new IllegalArgumentException("Invalid device address: " + address); - } - - return service.subrateModeRequest(clientIf, device, subrateMode); - } - - @Override - public void registerServer( - ParcelUuid uuid, - IBluetoothGattServerCallback callback, - boolean eattSupport, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.registerServer(uuid.getUuid(), callback, eattSupport, source); - } - - @Override - public void unregisterServer(int serverIf, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.unregisterServer(serverIf, source); - } - - @Override - public void serverConnect( - int serverIf, - String address, - int addressType, - boolean isDirect, - int transport, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.serverConnect(serverIf, address, addressType, isDirect, transport, source); - } - - @Override - public void serverDisconnect(int serverIf, String address, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.serverDisconnect(serverIf, address, source); - } - - @Override - public void serverSetPreferredPhy( - int serverIf, - String address, - int txPhy, - int rxPhy, - int phyOptions, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.serverSetPreferredPhy(serverIf, address, txPhy, rxPhy, phyOptions, source); - } - - @Override - public void serverReadPhy(int clientIf, String address, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.serverReadPhy(clientIf, address, source); - } - - @Override - public void addService(int serverIf, BluetoothGattService svc, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.addService(serverIf, svc, source); - } - - @Override - public void removeService(int serverIf, int handle, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.removeService(serverIf, handle, source); - } - - @Override - public void clearServices(int serverIf, AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.clearServices(serverIf, source); - } - - @Override - public void sendResponse( - int serverIf, - String address, - int requestId, - int status, - int offset, - byte[] value, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.sendResponse(serverIf, address, requestId, status, offset, value, source); - } - - @Override - public int sendNotification( - int serverIf, - String address, - int handle, - boolean confirm, - byte[] value, - AttributionSource source) { - GattService service = getService(); - if (service == null) { - return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } - return service.sendNotification(serverIf, address, handle, confirm, value, source); - } - - @Override - public void disconnectAll(AttributionSource source) { - GattService service = getService(); - if (service == null) { - return; - } - service.disconnectAll(source); - } - } - /************************************************************************** * Callback functions - CLIENT *************************************************************************/ @@ -1426,8 +956,8 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) List<BluetoothDevice> getDevicesMatchingConnectionStates( int[] states, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService getDevicesMatchingConnectionStates")) { + if (!checkConnectPermissionForDataDelivery( + this, source, TAG, "getDevicesMatchingConnectionStates")) { return Collections.emptyList(); } @@ -1492,12 +1022,10 @@ public class GattService extends ProfileService { IBluetoothGattCallback callback, boolean eatt_support, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService registerClient")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "registerClient")) { return; } - if (Flags.gattClientDynamicAllocation() - && mClientMap.countByAppUid(Binder.getCallingUid()) >= GATT_CLIENT_LIMIT_PER_APP) { + if (mClientMap.countByAppUid(Binder.getCallingUid()) >= GATT_CLIENT_LIMIT_PER_APP) { Log.w(TAG, "registerClient() - failed due to too many clients"); callbackToApp(() -> callback.onClientRegistered(BluetoothGatt.GATT_FAILURE, 0)); return; @@ -1522,8 +1050,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void unregisterClient(int clientIf, AttributionSource source, ContextMap.RemoveReason reason) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService unregisterClient")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "unregisterClient")) { return; } @@ -1551,8 +1078,7 @@ public class GattService extends ProfileService { boolean opportunistic, int phy, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService clientConnect")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "clientConnect")) { return; } @@ -1593,9 +1119,11 @@ public class GattService extends ProfileService { int preferredMtu = 0; - // Some applications expect MTU to be exchanged immediately on connections String packageName = source.getPackageName(); if (packageName != null) { + mAdapterService.addAssociatedPackage(getDevice(address), packageName); + + // Some apps expect MTU to be exchanged immediately on connections for (Map.Entry<String, Integer> entry : EARLY_MTU_EXCHANGE_PACKAGES.entrySet()) { if (packageName.contains(entry.getKey())) { preferredMtu = entry.getValue(); @@ -1640,8 +1168,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void clientDisconnect(int clientIf, String address, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService clientDisconnect")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "clientDisconnect")) { return; } @@ -1679,8 +1206,7 @@ public class GattService extends ProfileService { int rxPhy, int phyOptions, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService clientSetPreferredPhy")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "clientSetPreferredPhy")) { return; } @@ -1703,8 +1229,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void clientReadPhy(int clientIf, String address, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService clientReadPhy")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "clientReadPhy")) { return; } @@ -1722,8 +1247,8 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) synchronized List<ParcelUuid> getRegisteredServiceUuids(AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService getRegisteredServiceUuids")) { + if (!checkConnectPermissionForDataDelivery( + this, source, TAG, "getRegisteredServiceUuids")) { return Collections.emptyList(); } return mHandleMap.getEntries().stream() @@ -1733,8 +1258,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) List<String> getConnectedDevices(AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService getConnectedDevices")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "getConnectedDevices")) { return Collections.emptyList(); } @@ -1747,8 +1271,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void refreshDevice(int clientIf, String address, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService refreshDevice")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "refreshDevice")) { return; } @@ -1758,8 +1281,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void discoverServices(int clientIf, String address, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService discoverServices")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "discoverServices")) { return; } @@ -1784,8 +1306,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void discoverServiceByUuid(int clientIf, String address, UUID uuid, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService discoverServiceByUuid")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "discoverServiceByUuid")) { return; } @@ -1805,8 +1326,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void readCharacteristic( int clientIf, String address, int handle, int authReq, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService readCharacteristic")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "readCharacteristic")) { return; } @@ -1846,8 +1366,8 @@ public class GattService extends ProfileService { int endHandle, int authReq, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService readUsingCharacteristicUuid")) { + if (!checkConnectPermissionForDataDelivery( + this, source, TAG, "readUsingCharacteristicUuid")) { return; } @@ -1893,8 +1413,7 @@ public class GattService extends ProfileService { int authReq, byte[] value, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService writeCharacteristic")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "writeCharacteristic")) { return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; } @@ -1939,8 +1458,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void readDescriptor( int clientIf, String address, int handle, int authReq, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService readDescriptor")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "readDescriptor")) { return; } @@ -1977,8 +1495,7 @@ public class GattService extends ProfileService { int authReq, byte[] value, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService writeDescriptor")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "writeDescriptor")) { return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; } Log.v(TAG, "writeDescriptor() - address=" + toAnonymizedAddress(address)); @@ -2000,8 +1517,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void beginReliableWrite(int clientIf, String address, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService beginReliableWrite")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "beginReliableWrite")) { return; } @@ -2011,8 +1527,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void endReliableWrite(int clientIf, String address, boolean execute, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService endReliableWrite")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "endReliableWrite")) { return; } @@ -2033,8 +1548,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void registerForNotification( int clientIf, String address, int handle, boolean enable, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService registerForNotification")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "registerForNotification")) { return; } @@ -2072,8 +1586,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void readRemoteRssi(int clientIf, String address, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService readRemoteRssi")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "readRemoteRssi")) { return; } @@ -2083,8 +1596,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void configureMTU(int clientIf, String address, int mtu, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService configureMTU")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "configureMTU")) { return; } @@ -2102,8 +1614,8 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void connectionParameterUpdate( int clientIf, String address, int connectionPriority, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService connectionParameterUpdate")) { + if (!checkConnectPermissionForDataDelivery( + this, source, TAG, "connectionParameterUpdate")) { return; } @@ -2150,8 +1662,7 @@ public class GattService extends ProfileService { int minConnectionEventLen, int maxConnectionEventLen, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService leConnectionUpdate")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "leConnectionUpdate")) { return; } @@ -2184,7 +1695,7 @@ public class GattService extends ProfileService { maxConnectionEventLen); } - private int subrateModeRequest(int clientIf, BluetoothDevice device, int subrateMode) { + int subrateModeRequest(int clientIf, BluetoothDevice device, int subrateMode) { int subrateMin; int subrateMax; int maxLatency; @@ -2612,8 +2123,7 @@ public class GattService extends ProfileService { IBluetoothGattServerCallback callback, boolean eatt_support, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService registerServer")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "registerServer")) { return; } @@ -2625,8 +2135,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void unregisterServer(int serverIf, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService unregisterServer")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "unregisterServer")) { return; } @@ -2646,8 +2155,7 @@ public class GattService extends ProfileService { boolean isDirect, int transport, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService serverConnect")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "serverConnect")) { return; } @@ -2660,8 +2168,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void serverDisconnect(int serverIf, String address, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService serverDisconnect")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "serverDisconnect")) { return; } @@ -2684,8 +2191,7 @@ public class GattService extends ProfileService { int rxPhy, int phyOptions, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService serverSetPreferredPhy")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "serverSetPreferredPhy")) { return; } @@ -2708,8 +2214,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void serverReadPhy(int serverIf, String address, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService serverReadPhy")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "serverReadPhy")) { return; } @@ -2727,7 +2232,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void addService(int serverIf, BluetoothGattService service, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery(this, source, "GattService addService")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "addService")) { return; } @@ -2772,8 +2277,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void removeService(int serverIf, int handle, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService removeService")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "removeService")) { return; } @@ -2784,8 +2288,7 @@ public class GattService extends ProfileService { @RequiresPermission(BLUETOOTH_CONNECT) void clearServices(int serverIf, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService clearServices")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "clearServices")) { return; } @@ -2802,8 +2305,7 @@ public class GattService extends ProfileService { int offset, byte[] value, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService sendResponse")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "sendResponse")) { return; } @@ -2817,21 +2319,14 @@ public class GattService extends ProfileService { int handle = 0; Integer connId = 0; - if (!Flags.gattServerRequestsFix()) { - HandleMap.Entry entry = mHandleMap.getByRequestId(requestId); - if (entry != null) { - handle = entry.mHandle; - } - connId = mServerMap.connIdByAddress(serverIf, address); + HandleMap.RequestData requestData = mHandleMap.getRequestDataByRequestId(requestId); + if (requestData != null) { + handle = requestData.handle(); + connId = requestData.connId(); } else { - HandleMap.RequestData requestData = mHandleMap.getRequestDataByRequestId(requestId); - if (requestData != null) { - handle = requestData.handle(); - connId = requestData.connId(); - } else { - connId = mServerMap.connIdByAddress(serverIf, address); - } + connId = mServerMap.connIdByAddress(serverIf, address); } + mNativeInterface.gattServerSendResponse( serverIf, connId != null ? connId : 0, @@ -2852,8 +2347,7 @@ public class GattService extends ProfileService { boolean confirm, byte[] value, AttributionSource source) { - if (!Utils.checkConnectPermissionForDataDelivery( - this, source, "GattService sendNotification")) { + if (!checkConnectPermissionForDataDelivery(this, source, TAG, "sendNotification")) { return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; } diff --git a/android/app/src/com/android/bluetooth/gatt/GattServiceBinder.java b/android/app/src/com/android/bluetooth/gatt/GattServiceBinder.java new file mode 100644 index 0000000000..7be287677c --- /dev/null +++ b/android/app/src/com/android/bluetooth/gatt/GattServiceBinder.java @@ -0,0 +1,499 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.gatt; + +import static com.android.bluetooth.Utils.callerIsSystemOrActiveOrManagedUser; +import static com.android.bluetooth.Utils.checkConnectPermissionForDataDelivery; + +import static java.util.Objects.requireNonNull; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothStatusCodes; +import android.bluetooth.IBluetoothGatt; +import android.bluetooth.IBluetoothGattCallback; +import android.bluetooth.IBluetoothGattServerCallback; +import android.content.AttributionSource; +import android.os.ParcelUuid; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +/** Handlers for incoming service calls */ +class GattServiceBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder { + private static final String TAG = + GattServiceConfig.TAG_PREFIX + GattServiceBinder.class.getSimpleName(); + + private GattService mService; + + GattServiceBinder(GattService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + private GattService getService() { + GattService service = mService; + + if (!Utils.checkServiceAvailable(service, TAG)) { + return null; + } + + return service; + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states, source); + } + + @Override + public void registerClient( + ParcelUuid uuid, + IBluetoothGattCallback callback, + boolean eattSupport, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.registerClient(uuid.getUuid(), callback, eattSupport, source); + } + + @Override + public void unregisterClient(int clientIf, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.unregisterClient( + clientIf, source, ContextMap.RemoveReason.REASON_UNREGISTER_CLIENT); + } + + @Override + public void clientConnect( + int clientIf, + String address, + int addressType, + boolean isDirect, + int transport, + boolean opportunistic, + int phy, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.clientConnect( + clientIf, address, addressType, isDirect, transport, opportunistic, phy, source); + } + + @Override + public void clientDisconnect(int clientIf, String address, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.clientDisconnect(clientIf, address, source); + } + + @Override + public void clientSetPreferredPhy( + int clientIf, + String address, + int txPhy, + int rxPhy, + int phyOptions, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.clientSetPreferredPhy(clientIf, address, txPhy, rxPhy, phyOptions, source); + } + + @Override + public void clientReadPhy(int clientIf, String address, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.clientReadPhy(clientIf, address, source); + } + + @Override + public void refreshDevice(int clientIf, String address, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.refreshDevice(clientIf, address, source); + } + + @Override + public void discoverServices(int clientIf, String address, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.discoverServices(clientIf, address, source); + } + + @Override + public void discoverServiceByUuid( + int clientIf, String address, ParcelUuid uuid, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.discoverServiceByUuid(clientIf, address, uuid.getUuid(), source); + } + + @Override + public void readCharacteristic( + int clientIf, String address, int handle, int authReq, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.readCharacteristic(clientIf, address, handle, authReq, source); + } + + @Override + public void readUsingCharacteristicUuid( + int clientIf, + String address, + ParcelUuid uuid, + int startHandle, + int endHandle, + int authReq, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.readUsingCharacteristicUuid( + clientIf, address, uuid.getUuid(), startHandle, endHandle, authReq, source); + } + + @Override + public int writeCharacteristic( + int clientIf, + String address, + int handle, + int writeType, + int authReq, + byte[] value, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; + } + return service.writeCharacteristic( + clientIf, address, handle, writeType, authReq, value, source); + } + + @Override + public void readDescriptor( + int clientIf, String address, int handle, int authReq, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.readDescriptor(clientIf, address, handle, authReq, source); + } + + @Override + public int writeDescriptor( + int clientIf, + String address, + int handle, + int authReq, + byte[] value, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; + } + return service.writeDescriptor(clientIf, address, handle, authReq, value, source); + } + + @Override + public void beginReliableWrite(int clientIf, String address, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.beginReliableWrite(clientIf, address, source); + } + + @Override + public void endReliableWrite( + int clientIf, String address, boolean execute, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.endReliableWrite(clientIf, address, execute, source); + } + + @Override + public void registerForNotification( + int clientIf, String address, int handle, boolean enable, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.registerForNotification(clientIf, address, handle, enable, source); + } + + @Override + public void readRemoteRssi(int clientIf, String address, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.readRemoteRssi(clientIf, address, source); + } + + @Override + public void configureMTU(int clientIf, String address, int mtu, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.configureMTU(clientIf, address, mtu, source); + } + + @Override + public void connectionParameterUpdate( + int clientIf, String address, int connectionPriority, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.connectionParameterUpdate(clientIf, address, connectionPriority, source); + } + + @Override + public void leConnectionUpdate( + int clientIf, + String address, + int minConnectionInterval, + int maxConnectionInterval, + int peripheralLatency, + int supervisionTimeout, + int minConnectionEventLen, + int maxConnectionEventLen, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.leConnectionUpdate( + clientIf, + address, + minConnectionInterval, + maxConnectionInterval, + peripheralLatency, + supervisionTimeout, + minConnectionEventLen, + maxConnectionEventLen, + source); + } + + @Override + public int subrateModeRequest( + int clientIf, BluetoothDevice device, int subrateMode, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "subrateModeRequest")) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; + } + if (!checkConnectPermissionForDataDelivery(service, source, TAG, "subrateModeRequest")) { + return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; + } + + Utils.enforceCdmAssociationIfNotBluetoothPrivileged( + service, service.getCompanionDeviceManager(), source, device); + + if (subrateMode < BluetoothGatt.SUBRATE_REQUEST_MODE_BALANCED + || subrateMode > BluetoothGatt.SUBRATE_REQUEST_MODE_LOW_POWER) { + throw new IllegalArgumentException("Subrate Mode not within valid range"); + } + + requireNonNull(device); + String address = device.getAddress(); + if (!BluetoothAdapter.checkBluetoothAddress(address)) { + throw new IllegalArgumentException("Invalid device address: " + address); + } + + return service.subrateModeRequest(clientIf, device, subrateMode); + } + + @Override + public void registerServer( + ParcelUuid uuid, + IBluetoothGattServerCallback callback, + boolean eattSupport, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.registerServer(uuid.getUuid(), callback, eattSupport, source); + } + + @Override + public void unregisterServer(int serverIf, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.unregisterServer(serverIf, source); + } + + @Override + public void serverConnect( + int serverIf, + String address, + int addressType, + boolean isDirect, + int transport, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.serverConnect(serverIf, address, addressType, isDirect, transport, source); + } + + @Override + public void serverDisconnect(int serverIf, String address, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.serverDisconnect(serverIf, address, source); + } + + @Override + public void serverSetPreferredPhy( + int serverIf, + String address, + int txPhy, + int rxPhy, + int phyOptions, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.serverSetPreferredPhy(serverIf, address, txPhy, rxPhy, phyOptions, source); + } + + @Override + public void serverReadPhy(int clientIf, String address, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.serverReadPhy(clientIf, address, source); + } + + @Override + public void addService(int serverIf, BluetoothGattService svc, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.addService(serverIf, svc, source); + } + + @Override + public void removeService(int serverIf, int handle, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.removeService(serverIf, handle, source); + } + + @Override + public void clearServices(int serverIf, AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.clearServices(serverIf, source); + } + + @Override + public void sendResponse( + int serverIf, + String address, + int requestId, + int status, + int offset, + byte[] value, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.sendResponse(serverIf, address, requestId, status, offset, value, source); + } + + @Override + public int sendNotification( + int serverIf, + String address, + int handle, + boolean confirm, + byte[] value, + AttributionSource source) { + GattService service = getService(); + if (service == null) { + return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; + } + return service.sendNotification(serverIf, address, handle, confirm, value, source); + } + + @Override + public void disconnectAll(AttributionSource source) { + GattService service = getService(); + if (service == null) { + return; + } + service.disconnectAll(source); + } +} diff --git a/android/app/src/com/android/bluetooth/hap/HapClientService.java b/android/app/src/com/android/bluetooth/hap/HapClientService.java index 731f3da90c..9b8092763c 100644 --- a/android/app/src/com/android/bluetooth/hap/HapClientService.java +++ b/android/app/src/com/android/bluetooth/hap/HapClientService.java @@ -159,7 +159,7 @@ public class HapClientService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new HapClientBinder(this); + return new HapClientServiceBinder(this); } @Override diff --git a/android/app/src/com/android/bluetooth/hap/HapClientBinder.java b/android/app/src/com/android/bluetooth/hap/HapClientServiceBinder.java index eba1d9db4a..e036e43bb2 100644 --- a/android/app/src/com/android/bluetooth/hap/HapClientBinder.java +++ b/android/app/src/com/android/bluetooth/hap/HapClientServiceBinder.java @@ -36,21 +36,19 @@ import android.content.AttributionSource; import android.util.Log; import com.android.bluetooth.Utils; -import com.android.bluetooth.btservice.ProfileService; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; import com.android.internal.annotations.VisibleForTesting; import java.util.Collections; import java.util.List; -/** HapClientBinder class */ @VisibleForTesting -class HapClientBinder extends IBluetoothHapClient.Stub - implements ProfileService.IProfileServiceBinder { - private static final String TAG = HapClientBinder.class.getSimpleName(); +class HapClientServiceBinder extends IBluetoothHapClient.Stub implements IProfileServiceBinder { + private static final String TAG = HapClientServiceBinder.class.getSimpleName(); private HapClientService mService; - HapClientBinder(HapClientService svc) { + HapClientServiceBinder(HapClientService svc) { mService = svc; } @@ -62,7 +60,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) private HapClientService getService(AttributionSource source) { requireNonNull(source); - // Cache mService because it can change while getService is called HapClientService service = mService; if (Utils.isInstrumentationTestMode()) { @@ -86,7 +83,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub if (service == null) { return Collections.emptyList(); } - return service.getConnectedDevices(); } @@ -97,7 +93,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub if (service == null) { return Collections.emptyList(); } - return service.getDevicesMatchingConnectionStates(states); } @@ -109,7 +104,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - return service.getConnectionState(device); } @@ -139,7 +133,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - return service.getConnectionPolicy(device); } @@ -151,7 +144,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - return service.getActivePresetIndex(device); } @@ -164,7 +156,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - return service.getActivePresetInfo(device); } @@ -176,7 +167,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - return service.getHapGroup(device); } @@ -188,7 +178,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - service.selectPreset(device, presetIndex); } @@ -198,7 +187,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub if (service == null) { return; } - service.selectPresetForGroup(groupId, presetIndex); } @@ -210,7 +198,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - service.switchToNextPreset(device); } @@ -220,7 +207,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub if (service == null) { return; } - service.switchToNextPresetForGroup(groupId); } @@ -232,7 +218,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - service.switchToPreviousPreset(device); } @@ -242,7 +227,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub if (service == null) { return; } - service.switchToPreviousPresetForGroup(groupId); } @@ -255,7 +239,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - return service.getPresetInfo(device, presetIndex); } @@ -268,7 +251,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - return service.getAllPresetInfo(device); } @@ -280,7 +262,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(device); - return service.getFeatures(device); } @@ -294,7 +275,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub requireNonNull(device); requireNonNull(name); - service.setPresetName(device, presetIndex, name); } @@ -307,7 +287,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(name); - service.setPresetNameForGroup(groupId, presetIndex, name); } @@ -319,7 +298,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(callback); - service.registerCallback(callback); } @@ -331,7 +309,6 @@ class HapClientBinder extends IBluetoothHapClient.Stub } requireNonNull(callback); - service.unregisterCallback(callback); } } diff --git a/android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java b/android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java index 6af6323083..0bf2650bb1 100644 --- a/android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java +++ b/android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java @@ -17,7 +17,6 @@ package com.android.bluetooth.hearingaid; import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; @@ -27,14 +26,11 @@ import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; import static java.util.Objects.requireNonNull; -import android.annotation.RequiresPermission; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothHearingAid.AdvertisementServiceData; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; -import android.bluetooth.IBluetoothHearingAid; -import android.content.AttributionSource; import android.content.Intent; import android.media.AudioDeviceCallback; import android.media.AudioDeviceInfo; @@ -57,7 +53,6 @@ import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -130,7 +125,7 @@ public class HearingAidService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new BluetoothHearingAidBinder(this); + return new HearingAidServiceBinder(this); } @Override @@ -490,7 +485,7 @@ public class HearingAidService extends ProfileService { return mDeviceCapabilitiesMap.getOrDefault(device, -1); } - private AdvertisementServiceData getAdvertisementServiceData(BluetoothDevice device) { + AdvertisementServiceData getAdvertisementServiceData(BluetoothDevice device) { int capability = mAdapterService.getAshaCapability(device); int id = mAdapterService.getAshaTruncatedHiSyncId(device); if (capability < 0) { @@ -855,213 +850,6 @@ public class HearingAidService extends ProfileService { device, BluetoothProfile.HEARING_AID, toState, fromState); } - /** Binder object: must be a static class or memory leak may occur */ - @VisibleForTesting - static class BluetoothHearingAidBinder extends IBluetoothHearingAid.Stub - implements IProfileServiceBinder { - private HearingAidService mService; - - BluetoothHearingAidBinder(HearingAidService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private HearingAidService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - HearingAidService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - return service; - } - - @Override - public boolean connect(BluetoothDevice device, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.connect(device); - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.disconnect(device); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } - - @Override - public boolean setActiveDevice(BluetoothDevice device, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return false; - } - - if (device == null) { - return service.removeActiveDevice(false); - } else { - return service.setActiveDevice(device); - } - } - - @Override - public List<BluetoothDevice> getActiveDevices(AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getActiveDevices(); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectionPolicy(device); - } - - @Override - public void setVolume(int volume, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.setVolume(volume); - } - - @Override - public long getHiSyncId(BluetoothDevice device, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return BluetoothHearingAid.HI_SYNC_ID_INVALID; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getHiSyncId(device); - } - - @Override - public int getDeviceSide(BluetoothDevice device, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return BluetoothHearingAid.SIDE_UNKNOWN; - } - - int side = service.getCapabilities(device); - if (side != BluetoothHearingAid.SIDE_UNKNOWN) { - side &= 1; - } - - return side; - } - - @Override - public int getDeviceMode(BluetoothDevice device, AttributionSource source) { - HearingAidService service = getService(source); - if (service == null) { - return BluetoothHearingAid.MODE_UNKNOWN; - } - - int mode = service.getCapabilities(device); - if (mode != BluetoothHearingAid.MODE_UNKNOWN) { - mode = mode >> 1 & 1; - } - - return mode; - } - - @Override - public AdvertisementServiceData getAdvertisementServiceData( - BluetoothDevice device, AttributionSource source) { - HearingAidService service = mService; - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkScanPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getAdvertisementServiceData(device); - } - } - @Override public void dump(StringBuilder sb) { super.dump(sb); diff --git a/android/app/src/com/android/bluetooth/hearingaid/HearingAidServiceBinder.java b/android/app/src/com/android/bluetooth/hearingaid/HearingAidServiceBinder.java new file mode 100644 index 0000000000..de384fba5c --- /dev/null +++ b/android/app/src/com/android/bluetooth/hearingaid/HearingAidServiceBinder.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.hearingaid; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothHearingAid.AdvertisementServiceData; +import android.bluetooth.IBluetoothHearingAid; +import android.content.AttributionSource; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +class HearingAidServiceBinder extends IBluetoothHearingAid.Stub implements IProfileServiceBinder { + private static final String TAG = HearingAidServiceBinder.class.getSimpleName(); + + private HearingAidService mService; + + HearingAidServiceBinder(HearingAidService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private HearingAidService getService(AttributionSource source) { + HearingAidService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + return service; + } + + @Override + public boolean connect(BluetoothDevice device, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.connect(device); + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.disconnect(device); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public boolean setActiveDevice(BluetoothDevice device, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return false; + } + + if (device == null) { + return service.removeActiveDevice(false); + } else { + return service.setActiveDevice(device); + } + } + + @Override + public List<BluetoothDevice> getActiveDevices(AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getActiveDevices(); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionPolicy(device); + } + + @Override + public void setVolume(int volume, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setVolume(volume); + } + + @Override + public long getHiSyncId(BluetoothDevice device, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return BluetoothHearingAid.HI_SYNC_ID_INVALID; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getHiSyncId(device); + } + + @Override + public int getDeviceSide(BluetoothDevice device, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return BluetoothHearingAid.SIDE_UNKNOWN; + } + + int side = service.getCapabilities(device); + if (side != BluetoothHearingAid.SIDE_UNKNOWN) { + side &= 1; + } + + return side; + } + + @Override + public int getDeviceMode(BluetoothDevice device, AttributionSource source) { + HearingAidService service = getService(source); + if (service == null) { + return BluetoothHearingAid.MODE_UNKNOWN; + } + + int mode = service.getCapabilities(device); + if (mode != BluetoothHearingAid.MODE_UNKNOWN) { + mode = mode >> 1 & 1; + } + + return mode; + } + + @Override + public AdvertisementServiceData getAdvertisementServiceData( + BluetoothDevice device, AttributionSource source) { + HearingAidService service = mService; + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkScanPermissionForDataDelivery( + service, source, TAG, "getAdvertisementServiceData")) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getAdvertisementServiceData(device); + } +} diff --git a/android/app/src/com/android/bluetooth/hearingaid/OWNERS b/android/app/src/com/android/bluetooth/hearingaid/OWNERS deleted file mode 100644 index bbaa85ddbb..0000000000 --- a/android/app/src/com/android/bluetooth/hearingaid/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_hearingaid diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetNativeInterface.java b/android/app/src/com/android/bluetooth/hfp/HeadsetNativeInterface.java index 9d819eca5b..e3816ed636 100644 --- a/android/app/src/com/android/bluetooth/hfp/HeadsetNativeInterface.java +++ b/android/app/src/com/android/bluetooth/hfp/HeadsetNativeInterface.java @@ -24,7 +24,6 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; -import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.GuardedBy; /** @@ -84,16 +83,12 @@ public class HeadsetNativeInterface { return mAdapterService.getDeviceFromByte(address); } - private byte[] getByteAddress(BluetoothDevice device) { + private static byte[] getByteAddress(BluetoothDevice device) { if (device == null) { // Set bt_stack's active device to default if java layer set active device to null return Utils.getBytesFromAddress("00:00:00:00:00:00"); } - if (Flags.identityAddressNullIfNotKnown()) { - return Utils.getByteBrEdrAddress(device); - } else { - return mAdapterService.getByteIdentityAddress(device); - } + return Utils.getByteBrEdrAddress(device); } void onConnectionStateChanged(int state, byte[] address) { @@ -357,10 +352,11 @@ public class HeadsetNativeInterface { * Start voice recognition * * @param device target headset + * @param sendResult whether a BVRA response should be sent * @return True on success, False on failure */ - boolean startVoiceRecognition(BluetoothDevice device) { - return startVoiceRecognitionNative(getByteAddress(device)); + boolean startVoiceRecognition(BluetoothDevice device, boolean sendResult) { + return startVoiceRecognitionNative(getByteAddress(device), sendResult); } /** @@ -561,7 +557,7 @@ public class HeadsetNativeInterface { private native boolean isVoiceRecognitionSupportedNative(byte[] address); - private native boolean startVoiceRecognitionNative(byte[] address); + private native boolean startVoiceRecognitionNative(byte[] address, boolean sendResult); private native boolean stopVoiceRecognitionNative(byte[] address); diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java index 251f347ea2..c5ab1f8dde 100644 --- a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java +++ b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java @@ -17,8 +17,6 @@ package com.android.bluetooth.hfp; import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; -import static android.Manifest.permission.MODIFY_PHONE_STATE; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; @@ -33,15 +31,12 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.RequiresPermission; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothSinkAudioPolicy; import android.bluetooth.BluetoothStatusCodes; import android.bluetooth.BluetoothUuid; -import android.bluetooth.IBluetoothHeadset; -import android.content.AttributionSource; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -80,7 +75,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -237,7 +231,7 @@ public class HeadsetService extends ProfileService { @Override public IProfileServiceBinder initBinder() { - return new BluetoothHeadsetBinder(this); + return new HeadsetServiceBinder(this); } @Override @@ -516,303 +510,6 @@ public class HeadsetService extends ProfileService { } } - /** Handlers for incoming service calls */ - @VisibleForTesting - static class BluetoothHeadsetBinder extends IBluetoothHeadset.Stub - implements IProfileServiceBinder { - private HeadsetService mService; - - BluetoothHeadsetBinder(HeadsetService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private HeadsetService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - HeadsetService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - return service; - } - - @Override - public boolean connect(BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); - return service.connect(device); - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - return service.disconnect(device); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getConnectionPolicy(device); - } - - @Override - public boolean isNoiseReductionSupported(BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - return service.isNoiseReductionSupported(device); - } - - @Override - public boolean isVoiceRecognitionSupported( - BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - return service.isVoiceRecognitionSupported(device); - } - - @Override - public boolean startVoiceRecognition(BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - requireNonNull(device); - - return service.startVoiceRecognition(device); - } - - @Override - public boolean stopVoiceRecognition(BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - return service.stopVoiceRecognition(device); - } - - @Override - public boolean isAudioConnected(BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - return service.isAudioConnected(device); - } - - @Override - public int getAudioState(BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getAudioState(device); - } - - @Override - public int connectAudio(AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.connectAudio(); - } - - @Override - public int disconnectAudio(AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.disconnectAudio(); - } - - @Override - public void setAudioRouteAllowed(boolean allowed, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.setAudioRouteAllowed(allowed); - } - - @Override - public boolean getAudioRouteAllowed(AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getAudioRouteAllowed(); - } - - @Override - public void setForceScoAudio(boolean forced, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return; - } - - service.setForceScoAudio(forced); - } - - @Override - public boolean startScoUsingVirtualVoiceCall(AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.startScoUsingVirtualVoiceCall(); - } - - @Override - public boolean stopScoUsingVirtualVoiceCall(AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.stopScoUsingVirtualVoiceCall(); - } - - @Override - public boolean sendVendorSpecificResultCode( - BluetoothDevice device, String command, String arg, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - return service.sendVendorSpecificResultCode(device, command, arg); - } - - @Override - public boolean setActiveDevice(BluetoothDevice device, AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); - - return service.setActiveDevice(device); - } - - @Override - public BluetoothDevice getActiveDevice(AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return null; - } - - return service.getActiveDevice(); - } - - @Override - public boolean isInbandRingingEnabled(AttributionSource source) { - HeadsetService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.isInbandRingingEnabled(); - } - } - // API methods public static synchronized HeadsetService getHeadsetService() { if (sHeadsetService == null) { @@ -947,7 +644,6 @@ public class HeadsetService extends ProfileService { * @param states an array of states from {@link BluetoothProfile} * @return a list of devices matching the array of connection states */ - @VisibleForTesting public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { ArrayList<BluetoothDevice> devices = new ArrayList<>(); synchronized (mStateMachines) { @@ -1659,7 +1355,6 @@ public class HeadsetService extends ProfileService { } } - @VisibleForTesting boolean startScoUsingVirtualVoiceCall() { Log.i(TAG, "startScoUsingVirtualVoiceCall: " + Utils.getUidPidString()); synchronized (mStateMachines) { @@ -2134,8 +1829,7 @@ public class HeadsetService extends ProfileService { } } - private boolean sendVendorSpecificResultCode( - BluetoothDevice device, String command, String arg) { + boolean sendVendorSpecificResultCode(BluetoothDevice device, String command, String arg) { synchronized (mStateMachines) { final HeadsetStateMachine stateMachine = mStateMachines.get(device); if (stateMachine == null) { @@ -2396,9 +2090,10 @@ public class HeadsetService extends ProfileService { // Do it here because some controllers cannot handle SCO and CIS // co-existence see {@link LeAudioService#setInactiveForHfpHandover} LeAudioService leAudioService = mFactory.getLeAudioService(); - boolean isLeAudioConnectedDeviceNotActive = leAudioService != null - && !leAudioService.getConnectedDevices().isEmpty() - && leAudioService.getActiveDevices().get(0) == null; + boolean isLeAudioConnectedDeviceNotActive = + leAudioService != null + && !leAudioService.getConnectedDevices().isEmpty() + && leAudioService.getActiveDevices().get(0) == null; // usually controller limitation cause CONNECTING -> DISCONNECTED, so only // resume LE audio active device if it is HFP audio only and SCO disconnected if (fromState != BluetoothHeadset.STATE_AUDIO_CONNECTING diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetServiceBinder.java b/android/app/src/com/android/bluetooth/hfp/HeadsetServiceBinder.java new file mode 100644 index 0000000000..d93ad5dc5f --- /dev/null +++ b/android/app/src/com/android/bluetooth/hfp/HeadsetServiceBinder.java @@ -0,0 +1,319 @@ +/* + * Copyright (C) 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. + */ + +package com.android.bluetooth.hfp; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.Manifest.permission.MODIFY_PHONE_STATE; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import static java.util.Objects.requireNonNull; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothStatusCodes; +import android.bluetooth.IBluetoothHeadset; +import android.content.AttributionSource; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +class HeadsetServiceBinder extends IBluetoothHeadset.Stub implements IProfileServiceBinder { + private static final String TAG = HeadsetServiceBinder.class.getSimpleName(); + + private HeadsetService mService; + + HeadsetServiceBinder(HeadsetService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private HeadsetService getService(AttributionSource source) { + HeadsetService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + return service; + } + + @Override + public boolean connect(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); + return service.connect(device); + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + return service.disconnect(device); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionPolicy(device); + } + + @Override + public boolean isNoiseReductionSupported(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + return service.isNoiseReductionSupported(device); + } + + @Override + public boolean isVoiceRecognitionSupported(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + return service.isVoiceRecognitionSupported(device); + } + + @Override + public boolean startVoiceRecognition(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + + requireNonNull(device); + return service.startVoiceRecognition(device); + } + + @Override + public boolean stopVoiceRecognition(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + return service.stopVoiceRecognition(device); + } + + @Override + public boolean isAudioConnected(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + return service.isAudioConnected(device); + } + + @Override + public int getAudioState(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getAudioState(device); + } + + @Override + public int connectAudio(AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.connectAudio(); + } + + @Override + public int disconnectAudio(AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.disconnectAudio(); + } + + @Override + public void setAudioRouteAllowed(boolean allowed, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setAudioRouteAllowed(allowed); + } + + @Override + public boolean getAudioRouteAllowed(AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getAudioRouteAllowed(); + } + + @Override + public void setForceScoAudio(boolean forced, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return; + } + service.setForceScoAudio(forced); + } + + @Override + public boolean startScoUsingVirtualVoiceCall(AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + return service.startScoUsingVirtualVoiceCall(); + } + + @Override + public boolean stopScoUsingVirtualVoiceCall(AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + return service.stopScoUsingVirtualVoiceCall(); + } + + @Override + public boolean sendVendorSpecificResultCode( + BluetoothDevice device, String command, String arg, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + return service.sendVendorSpecificResultCode(device, command, arg); + } + + @Override + public boolean setActiveDevice(BluetoothDevice device, AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); + return service.setActiveDevice(device); + } + + @Override + public BluetoothDevice getActiveDevice(AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return null; + } + return service.getActiveDevice(); + } + + @Override + public boolean isInbandRingingEnabled(AttributionSource source) { + HeadsetService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.isInbandRingingEnabled(); + } +} diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java index 4e8e14a547..6ea741af32 100644 --- a/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java +++ b/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java @@ -1044,7 +1044,8 @@ class HeadsetStateMachine extends StateMachine { + " is not currentDevice"); break; } - if (!mNativeInterface.startVoiceRecognition(mDevice)) { + if (!mNativeInterface.startVoiceRecognition( + mDevice, /* sendResult */ true)) { stateLogW("Failed to start voice recognition"); break; } @@ -1122,6 +1123,9 @@ class HeadsetStateMachine extends StateMachine { ? HeadsetHalConstants.AT_RESPONSE_OK : HeadsetHalConstants.AT_RESPONSE_ERROR, 0); + if (Utils.isScoManagedByAudioEnabled()) { + mNativeInterface.startVoiceRecognition(mDevice, /* sendResult */ false); + } break; } case DIALING_OUT_RESULT: diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java index 9c0e416168..7d3a5ff43f 100644 --- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java +++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java @@ -16,11 +16,8 @@ package com.android.bluetooth.hfpclient; -import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; -import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; import static android.bluetooth.BluetoothProfile.STATE_CONNECTING; import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; @@ -28,15 +25,11 @@ import static android.content.pm.PackageManager.FEATURE_WATCH; import static java.util.Objects.requireNonNull; -import android.annotation.RequiresPermission; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothHeadsetClientCall; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothSinkAudioPolicy; import android.bluetooth.BluetoothStatusCodes; -import android.bluetooth.IBluetoothHeadsetClient; -import android.content.AttributionSource; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -58,7 +51,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -145,7 +137,7 @@ public class HeadsetClientService extends ProfileService { @Override public IProfileServiceBinder initBinder() { - return new BluetoothHeadsetClientBinder(this); + return new HeadsetClientServiceBinder(this); } @Override @@ -290,340 +282,6 @@ public class HeadsetClientService extends ProfileService { call.isInBandRing()); } - /** Handlers for incoming service calls */ - @VisibleForTesting - static class BluetoothHeadsetClientBinder extends IBluetoothHeadsetClient.Stub - implements IProfileServiceBinder { - private HeadsetClientService mService; - - BluetoothHeadsetClientBinder(HeadsetClientService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private HeadsetClientService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - HeadsetClientService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - return service; - } - - @Override - public boolean connect(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.connect(device); - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.disconnect(device); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return STATE_DISCONNECTED; - } - - service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectionState(device); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); - - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectionPolicy(device); - } - - @Override - public boolean startVoiceRecognition(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.startVoiceRecognition(device); - } - - @Override - public boolean stopVoiceRecognition(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.stopVoiceRecognition(device); - } - - @Override - public int getAudioState(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; - } - - return service.getAudioState(device); - } - - @Override - public void setAudioRouteAllowed( - BluetoothDevice device, boolean allowed, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - Log.w(TAG, "Service handle is null for setAudioRouteAllowed!"); - return; - } - - service.setAudioRouteAllowed(device, allowed); - } - - @Override - public boolean getAudioRouteAllowed(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - Log.w(TAG, "Service handle is null for getAudioRouteAllowed!"); - return false; - } - - return service.getAudioRouteAllowed(device); - } - - @Override - public boolean connectAudio(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.connectAudio(device); - } - - @Override - public boolean disconnectAudio(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.disconnectAudio(device); - } - - @Override - public boolean acceptCall(BluetoothDevice device, int flag, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.acceptCall(device, flag); - } - - @Override - public boolean rejectCall(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.rejectCall(device); - } - - @Override - public boolean holdCall(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.holdCall(device); - } - - @Override - public boolean terminateCall( - BluetoothDevice device, BluetoothHeadsetClientCall call, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - Log.w(TAG, "service is null"); - return false; - } - - return service.terminateCall(device, call != null ? call.getUUID() : null); - } - - @Override - public boolean explicitCallTransfer(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.explicitCallTransfer(device); - } - - @Override - public boolean enterPrivateMode( - BluetoothDevice device, int index, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.enterPrivateMode(device, index); - } - - @Override - public BluetoothHeadsetClientCall dial( - BluetoothDevice device, String number, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return null; - } - - return toLegacyCall(service.dial(device, number)); - } - - @Override - public List<BluetoothHeadsetClientCall> getCurrentCalls( - BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - List<BluetoothHeadsetClientCall> currentCalls = new ArrayList<>(); - if (service == null) { - return currentCalls; - } - - List<HfpClientCall> calls = service.getCurrentCalls(device); - if (calls != null) { - for (HfpClientCall call : calls) { - currentCalls.add(toLegacyCall(call)); - } - } - return currentCalls; - } - - @Override - public boolean sendDTMF(BluetoothDevice device, byte code, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.sendDTMF(device, code); - } - - @Override - public boolean getLastVoiceTagNumber(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.getLastVoiceTagNumber(device); - } - - @Override - public Bundle getCurrentAgEvents(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return null; - } - - service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getCurrentAgEvents(device); - } - - @Override - public boolean sendVendorAtCommand( - BluetoothDevice device, int vendorId, String atCommand, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return false; - } - - return service.sendVendorAtCommand(device, vendorId, atCommand); - } - - @Override - public Bundle getCurrentAgFeatures(BluetoothDevice device, AttributionSource source) { - HeadsetClientService service = getService(source); - if (service == null) { - return null; - } - - return service.getCurrentAgFeaturesBundle(device); - } - } - // API methods public static synchronized HeadsetClientService getHeadsetClientService() { if (sHeadsetClientService == null) { diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientServiceBinder.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientServiceBinder.java new file mode 100644 index 0000000000..3232fccd4f --- /dev/null +++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientServiceBinder.java @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.hfpclient; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadsetClient; +import android.bluetooth.BluetoothHeadsetClientCall; +import android.bluetooth.IBluetoothHeadsetClient; +import android.content.AttributionSource; +import android.os.Bundle; +import android.util.Log; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** Handlers for incoming service calls */ +class HeadsetClientServiceBinder extends IBluetoothHeadsetClient.Stub + implements IProfileServiceBinder { + private static final String TAG = HeadsetClientServiceBinder.class.getSimpleName(); + + private HeadsetClientService mService; + + HeadsetClientServiceBinder(HeadsetClientService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private HeadsetClientService getService(AttributionSource source) { + HeadsetClientService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + return service; + } + + @Override + public boolean connect(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.connect(device); + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.disconnect(device); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + + service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + + service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return STATE_DISCONNECTED; + } + + service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionState(device); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + + service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionPolicy(device); + } + + @Override + public boolean startVoiceRecognition(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.startVoiceRecognition(device); + } + + @Override + public boolean stopVoiceRecognition(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.stopVoiceRecognition(device); + } + + @Override + public int getAudioState(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; + } + return service.getAudioState(device); + } + + @Override + public void setAudioRouteAllowed( + BluetoothDevice device, boolean allowed, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + Log.w(TAG, "Service handle is null for setAudioRouteAllowed!"); + return; + } + service.setAudioRouteAllowed(device, allowed); + } + + @Override + public boolean getAudioRouteAllowed(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + Log.w(TAG, "Service handle is null for getAudioRouteAllowed!"); + return false; + } + return service.getAudioRouteAllowed(device); + } + + @Override + public boolean connectAudio(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.connectAudio(device); + } + + @Override + public boolean disconnectAudio(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.disconnectAudio(device); + } + + @Override + public boolean acceptCall(BluetoothDevice device, int flag, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.acceptCall(device, flag); + } + + @Override + public boolean rejectCall(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.rejectCall(device); + } + + @Override + public boolean holdCall(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.holdCall(device); + } + + @Override + public boolean terminateCall( + BluetoothDevice device, BluetoothHeadsetClientCall call, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + Log.w(TAG, "service is null"); + return false; + } + return service.terminateCall(device, call != null ? call.getUUID() : null); + } + + @Override + public boolean explicitCallTransfer(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.explicitCallTransfer(device); + } + + @Override + public boolean enterPrivateMode(BluetoothDevice device, int index, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.enterPrivateMode(device, index); + } + + @Override + public BluetoothHeadsetClientCall dial( + BluetoothDevice device, String number, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return null; + } + return HeadsetClientService.toLegacyCall(service.dial(device, number)); + } + + @Override + public List<BluetoothHeadsetClientCall> getCurrentCalls( + BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + List<BluetoothHeadsetClientCall> currentCalls = new ArrayList<>(); + if (service == null) { + return currentCalls; + } + + List<HfpClientCall> calls = service.getCurrentCalls(device); + if (calls != null) { + for (HfpClientCall call : calls) { + currentCalls.add(HeadsetClientService.toLegacyCall(call)); + } + } + return currentCalls; + } + + @Override + public boolean sendDTMF(BluetoothDevice device, byte code, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.sendDTMF(device, code); + } + + @Override + public boolean getLastVoiceTagNumber(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.getLastVoiceTagNumber(device); + } + + @Override + public Bundle getCurrentAgEvents(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return null; + } + + service.enforceCallingPermission(BLUETOOTH_PRIVILEGED, null); + return service.getCurrentAgEvents(device); + } + + @Override + public boolean sendVendorAtCommand( + BluetoothDevice device, int vendorId, String atCommand, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return false; + } + return service.sendVendorAtCommand(device, vendorId, atCommand); + } + + @Override + public Bundle getCurrentAgFeatures(BluetoothDevice device, AttributionSource source) { + HeadsetClientService service = getService(source); + if (service == null) { + return null; + } + return service.getCurrentAgFeaturesBundle(device); + } +} diff --git a/android/app/src/com/android/bluetooth/hfpclient/NativeInterface.java b/android/app/src/com/android/bluetooth/hfpclient/NativeInterface.java index fbb68747fe..bcbb49fba6 100644 --- a/android/app/src/com/android/bluetooth/hfpclient/NativeInterface.java +++ b/android/app/src/com/android/bluetooth/hfpclient/NativeInterface.java @@ -27,7 +27,6 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; -import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -334,12 +333,8 @@ public class NativeInterface { return mAdapterService.getDeviceFromByte(address); } - private byte[] getByteAddress(BluetoothDevice device) { - if (Flags.identityAddressNullIfNotKnown()) { - return Utils.getByteBrEdrAddress(device); - } else { - return mAdapterService.getByteIdentityAddress(device); - } + private static byte[] getByteAddress(BluetoothDevice device) { + return Utils.getByteBrEdrAddress(device); } // Callbacks from the native back into the java framework. All callbacks are routed via the diff --git a/android/app/src/com/android/bluetooth/hfpclient/OWNERS b/android/app/src/com/android/bluetooth/hfpclient/OWNERS deleted file mode 100644 index ecd59038a1..0000000000 --- a/android/app/src/com/android/bluetooth/hfpclient/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_automotive diff --git a/android/app/src/com/android/bluetooth/hid/HidDeviceNativeInterface.java b/android/app/src/com/android/bluetooth/hid/HidDeviceNativeInterface.java index 2ca9078103..dc269b7abf 100644 --- a/android/app/src/com/android/bluetooth/hid/HidDeviceNativeInterface.java +++ b/android/app/src/com/android/bluetooth/hid/HidDeviceNativeInterface.java @@ -29,7 +29,6 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; -import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.VisibleForTesting; /** HID Device Native Interface to/from JNI. */ @@ -123,7 +122,7 @@ public class HidDeviceNativeInterface { * @return the result of the native call */ public boolean connect(BluetoothDevice device) { - return connectNative(getByteAddress(device)); + return connectNative(Utils.getByteBrEdrAddress(device)); } /** @@ -243,14 +242,6 @@ public class HidDeviceNativeInterface { return mAdapterService.getDeviceFromByte(address); } - private byte[] getByteAddress(BluetoothDevice device) { - if (Flags.identityAddressNullIfNotKnown()) { - return Utils.getByteBrEdrAddress(device); - } else { - return mAdapterService.getByteIdentityAddress(device); - } - } - private native void initNative(); private native void cleanupNative(); diff --git a/android/app/src/com/android/bluetooth/hid/HidDeviceService.java b/android/app/src/com/android/bluetooth/hid/HidDeviceService.java index 2c2f11940e..d3d84d9630 100644 --- a/android/app/src/com/android/bluetooth/hid/HidDeviceService.java +++ b/android/app/src/com/android/bluetooth/hid/HidDeviceService.java @@ -34,9 +34,7 @@ import android.bluetooth.BluetoothHidDevice; import android.bluetooth.BluetoothHidDeviceAppQosSettings; import android.bluetooth.BluetoothHidDeviceAppSdpSettings; import android.bluetooth.BluetoothProfile; -import android.bluetooth.IBluetoothHidDevice; import android.bluetooth.IBluetoothHidDeviceCallback; -import android.content.AttributionSource; import android.content.Intent; import android.os.Binder; import android.os.Handler; @@ -50,15 +48,12 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; -import com.android.bluetooth.btservice.MetricsLogger; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.storage.DatabaseManager; import com.android.internal.annotations.VisibleForTesting; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.NoSuchElementException; @@ -328,204 +323,9 @@ public class HidDeviceService extends ProfileService { } }; - @VisibleForTesting - static class BluetoothHidDeviceBinder extends IBluetoothHidDevice.Stub - implements IProfileServiceBinder { - - private static final String TAG = BluetoothHidDeviceBinder.class.getSimpleName(); - - private HidDeviceService mService; - - BluetoothHidDeviceBinder(HidDeviceService service) { - mService = service; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private HidDeviceService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - HidDeviceService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - return service; - } - - @Override - public boolean registerApp( - BluetoothHidDeviceAppSdpSettings sdp, - BluetoothHidDeviceAppQosSettings inQos, - BluetoothHidDeviceAppQosSettings outQos, - IBluetoothHidDeviceCallback callback, - AttributionSource source) { - Log.d(TAG, "registerApp()"); - - HidDeviceService service = getService(source); - if (service == null) { - return false; - } - - return service.registerApp(sdp, inQos, outQos, callback); - } - - @Override - public boolean unregisterApp(AttributionSource source) { - Log.d(TAG, "unregisterApp()"); - - HidDeviceService service = getService(source); - if (service == null) { - return false; - } - - return service.unregisterApp(); - } - - @Override - public boolean sendReport( - BluetoothDevice device, int id, byte[] data, AttributionSource source) { - Log.d(TAG, "sendReport(): device=" + device + " id=" + id); - - HidDeviceService service = getService(source); - if (service == null) { - return false; - } - - return service.sendReport(device, id, data); - } - - @Override - public boolean replyReport( - BluetoothDevice device, byte type, byte id, byte[] data, AttributionSource source) { - Log.d(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id); - - HidDeviceService service = getService(source); - if (service == null) { - return false; - } - - return service.replyReport(device, type, id, data); - } - - @Override - public boolean unplug(BluetoothDevice device, AttributionSource source) { - Log.d(TAG, "unplug(): device=" + device); - - HidDeviceService service = getService(source); - if (service == null) { - return false; - } - - return service.unplug(device); - } - - @Override - public boolean connect(BluetoothDevice device, AttributionSource source) { - Log.d(TAG, "connect(): device=" + device); - - HidDeviceService service = getService(source); - if (service == null) { - return false; - } - - return service.connect(device); - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - Log.d(TAG, "disconnect(): device=" + device); - - HidDeviceService service = getService(source); - if (service == null) { - return false; - } - - return service.disconnect(device); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - Log.d( - TAG, - "setConnectionPolicy():" - + (" device=" + device) - + (" connectionPolicy=" + connectionPolicy)); - - HidDeviceService service = getService(source); - if (service == null) { - return false; - } - - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public boolean reportError(BluetoothDevice device, byte error, AttributionSource source) { - Log.d(TAG, "reportError(): device=" + device + " error=" + error); - - HidDeviceService service = getService(source); - if (service == null) { - return false; - } - - return service.reportError(device, error); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - Log.d(TAG, "getConnectionState(): device=" + device); - - HidDeviceService service = getService(source); - if (service == null) { - return BluetoothHidDevice.STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - Log.d(TAG, "getConnectedDevices()"); - - return getDevicesMatchingConnectionStates(new int[] {STATE_CONNECTED}, source); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - Log.d(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states)); - - HidDeviceService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public String getUserAppName(AttributionSource source) { - HidDeviceService service = getService(source); - if (service == null) { - return ""; - } - return service.getUserAppName(); - } - } - @Override protected IProfileServiceBinder initBinder() { - return new BluetoothHidDeviceBinder(this); + return new HidDeviceServiceBinder(this); } private boolean checkDevice(BluetoothDevice device) { diff --git a/android/app/src/com/android/bluetooth/hid/HidDeviceServiceBinder.java b/android/app/src/com/android/bluetooth/hid/HidDeviceServiceBinder.java new file mode 100644 index 0000000000..0cd0e1d301 --- /dev/null +++ b/android/app/src/com/android/bluetooth/hid/HidDeviceServiceBinder.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.hid; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHidDevice; +import android.bluetooth.BluetoothHidDeviceAppQosSettings; +import android.bluetooth.BluetoothHidDeviceAppSdpSettings; +import android.bluetooth.IBluetoothHidDevice; +import android.bluetooth.IBluetoothHidDeviceCallback; +import android.content.AttributionSource; +import android.util.Log; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +class HidDeviceServiceBinder extends IBluetoothHidDevice.Stub implements IProfileServiceBinder { + private static final String TAG = HidDeviceServiceBinder.class.getSimpleName(); + + private HidDeviceService mService; + + HidDeviceServiceBinder(HidDeviceService service) { + mService = service; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private HidDeviceService getService(AttributionSource source) { + // Cache mService because it can change while getService is called + HidDeviceService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + return service; + } + + @Override + public boolean registerApp( + BluetoothHidDeviceAppSdpSettings sdp, + BluetoothHidDeviceAppQosSettings inQos, + BluetoothHidDeviceAppQosSettings outQos, + IBluetoothHidDeviceCallback callback, + AttributionSource source) { + Log.d(TAG, "registerApp()"); + + HidDeviceService service = getService(source); + if (service == null) { + return false; + } + return service.registerApp(sdp, inQos, outQos, callback); + } + + @Override + public boolean unregisterApp(AttributionSource source) { + Log.d(TAG, "unregisterApp()"); + + HidDeviceService service = getService(source); + if (service == null) { + return false; + } + return service.unregisterApp(); + } + + @Override + public boolean sendReport( + BluetoothDevice device, int id, byte[] data, AttributionSource source) { + Log.d(TAG, "sendReport(): device=" + device + " id=" + id); + + HidDeviceService service = getService(source); + if (service == null) { + return false; + } + return service.sendReport(device, id, data); + } + + @Override + public boolean replyReport( + BluetoothDevice device, byte type, byte id, byte[] data, AttributionSource source) { + Log.d(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id); + + HidDeviceService service = getService(source); + if (service == null) { + return false; + } + return service.replyReport(device, type, id, data); + } + + @Override + public boolean unplug(BluetoothDevice device, AttributionSource source) { + Log.d(TAG, "unplug(): device=" + device); + + HidDeviceService service = getService(source); + if (service == null) { + return false; + } + return service.unplug(device); + } + + @Override + public boolean connect(BluetoothDevice device, AttributionSource source) { + Log.d(TAG, "connect(): device=" + device); + + HidDeviceService service = getService(source); + if (service == null) { + return false; + } + return service.connect(device); + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + Log.d(TAG, "disconnect(): device=" + device); + + HidDeviceService service = getService(source); + if (service == null) { + return false; + } + return service.disconnect(device); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + Log.d( + TAG, + "setConnectionPolicy():" + + (" device=" + device) + + (" connectionPolicy=" + connectionPolicy)); + + HidDeviceService service = getService(source); + if (service == null) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public boolean reportError(BluetoothDevice device, byte error, AttributionSource source) { + Log.d(TAG, "reportError(): device=" + device + " error=" + error); + + HidDeviceService service = getService(source); + if (service == null) { + return false; + } + return service.reportError(device, error); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + Log.d(TAG, "getConnectionState(): device=" + device); + + HidDeviceService service = getService(source); + if (service == null) { + return BluetoothHidDevice.STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + Log.d(TAG, "getConnectedDevices()"); + + return getDevicesMatchingConnectionStates(new int[] {STATE_CONNECTED}, source); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + Log.d(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states)); + + HidDeviceService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public String getUserAppName(AttributionSource source) { + HidDeviceService service = getService(source); + if (service == null) { + return ""; + } + return service.getUserAppName(); + } +} diff --git a/android/app/src/com/android/bluetooth/hid/HidHostService.java b/android/app/src/com/android/bluetooth/hid/HidHostService.java index 3a29ed5b62..68c2be4a8b 100644 --- a/android/app/src/com/android/bluetooth/hid/HidHostService.java +++ b/android/app/src/com/android/bluetooth/hid/HidHostService.java @@ -17,7 +17,6 @@ package com.android.bluetooth.hid; import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; @@ -27,14 +26,11 @@ import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTING; import static java.util.Objects.requireNonNull; -import android.annotation.RequiresPermission; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHidHost; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProtoEnums; import android.bluetooth.BluetoothUuid; -import android.bluetooth.IBluetoothHidHost; -import android.content.AttributionSource; import android.content.Intent; import android.os.Bundle; import android.os.Handler; @@ -145,7 +141,7 @@ public class HidHostService extends ProfileService { @Override public IProfileServiceBinder initBinder() { - return new BluetoothHidHostBinder(this); + return new HidHostServiceBinder(this); } @Override @@ -166,14 +162,6 @@ public class HidHostService extends ProfileService { setHidHostService(null); } - private byte[] getIdentityAddress(BluetoothDevice device) { - if (Flags.identityAddressNullIfNotKnown()) { - return Utils.getByteBrEdrAddress(mAdapterService, device); - } else { - return mAdapterService.getByteIdentityAddress(device); - } - } - private byte[] getByteAddress(BluetoothDevice device, int transport) { final ParcelUuid[] uuids = mAdapterService.getRemoteUuids(device); @@ -181,14 +169,14 @@ public class HidHostService extends ProfileService { // Use pseudo address when HOGP is to be used return Utils.getByteAddress(device); } else if (transport == BluetoothDevice.TRANSPORT_BREDR) { - // Use identity address if HID is to be used - return getIdentityAddress(device); + // Use BR/EDR address if HID is to be used + return Utils.getByteBrEdrAddress(mAdapterService, device); } else { // BluetoothDevice.TRANSPORT_AUTO boolean hidSupported = Utils.arrayContains(uuids, BluetoothUuid.HID); // Prefer HID over HOGP if (hidSupported) { - // Use identity address if HID is available - return getIdentityAddress(device); + // Use BR/EDR address if HID is available + return Utils.getByteBrEdrAddress(mAdapterService, device); } else { // Otherwise use pseudo address return Utils.getByteAddress(device); @@ -713,207 +701,6 @@ public class HidHostService extends ProfileService { return true; } - @VisibleForTesting - static class BluetoothHidHostBinder extends IBluetoothHidHost.Stub - implements IProfileServiceBinder { - private HidHostService mService; - - BluetoothHidHostBinder(HidHostService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private HidHostService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - HidHostService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - return service; - } - - @Override - public boolean connect(BluetoothDevice device, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.connect(device); - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.disconnect(device); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return STATE_DISCONNECTED; - } - return service.getConnectionState(device); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - return getDevicesMatchingConnectionStates(new int[] {STATE_CONNECTED}, source); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getConnectionPolicy(device); - } - - @Override - public boolean setPreferredTransport( - BluetoothDevice device, int transport, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.setPreferredTransport(device, transport); - } - - @Override - public int getPreferredTransport(BluetoothDevice device, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return BluetoothDevice.TRANSPORT_AUTO; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getPreferredTransport(device); - } - - /* The following APIs regarding test app for compliance */ - @Override - public boolean getProtocolMode(BluetoothDevice device, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - return service.getProtocolMode(device); - } - - @Override - public boolean virtualUnplug(BluetoothDevice device, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - return service.virtualUnplug(device); - } - - @Override - public boolean setProtocolMode( - BluetoothDevice device, int protocolMode, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - return service.setProtocolMode(device, protocolMode); - } - - @Override - public boolean getReport( - BluetoothDevice device, - byte reportType, - byte reportId, - int bufferSize, - AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - return service.getReport(device, reportType, reportId, bufferSize); - } - - @Override - public boolean setReport( - BluetoothDevice device, byte reportType, String report, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - return service.setReport(device, reportType, report); - } - - @Override - public boolean sendData(BluetoothDevice device, String report, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - return service.sendData(device, report); - } - - @Override - public boolean setIdleTime( - BluetoothDevice device, byte idleTime, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - return service.setIdleTime(device, idleTime); - } - - @Override - public boolean getIdleTime(BluetoothDevice device, AttributionSource source) { - HidHostService service = getService(source); - if (service == null) { - return false; - } - return service.getIdleTime(device); - } - } - ; - // APIs /** @@ -982,7 +769,6 @@ public class HidHostService extends ProfileService { return STATE_DISCONNECTED; } - @VisibleForTesting List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { Log.d(TAG, "getDevicesMatchingConnectionStates()"); return mInputDevices.entrySet().stream() @@ -1073,7 +859,6 @@ public class HidHostService extends ProfileService { /** * @see BluetoothHidHost#getPreferredTransport */ - @VisibleForTesting int getPreferredTransport(BluetoothDevice device) { Log.d(TAG, "getPreferredTransport: device=" + device); @@ -1082,7 +867,6 @@ public class HidHostService extends ProfileService { } /* The following APIs regarding test app for compliance */ - @VisibleForTesting boolean getProtocolMode(BluetoothDevice device) { Log.d(TAG, "getProtocolMode: device=" + device); int state = this.getConnectionState(device); @@ -1094,7 +878,6 @@ public class HidHostService extends ProfileService { return true; } - @VisibleForTesting boolean virtualUnplug(BluetoothDevice device) { Log.d(TAG, "virtualUnplug: device=" + device); int state = this.getConnectionState(device); @@ -1106,7 +889,6 @@ public class HidHostService extends ProfileService { return true; } - @VisibleForTesting boolean setProtocolMode(BluetoothDevice device, int protocolMode) { Log.d(TAG, "setProtocolMode: device=" + device); int state = this.getConnectionState(device); @@ -1120,7 +902,6 @@ public class HidHostService extends ProfileService { return true; } - @VisibleForTesting boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) { Log.d(TAG, "getReport: device=" + device); int state = this.getConnectionState(device); @@ -1138,7 +919,6 @@ public class HidHostService extends ProfileService { return true; } - @VisibleForTesting boolean setReport(BluetoothDevice device, byte reportType, String report) { Log.d(TAG, "setReport: device=" + device); int state = this.getConnectionState(device); @@ -1155,7 +935,6 @@ public class HidHostService extends ProfileService { return true; } - @VisibleForTesting boolean sendData(BluetoothDevice device, String report) { Log.d(TAG, "sendData: device=" + device); int state = this.getConnectionState(device); @@ -1393,8 +1172,9 @@ public class HidHostService extends ProfileService { // Allow this connection only if the device is bonded. Any attempt to connect // while bonding would potentially lead to an unauthorized connection. if (bondState != BluetoothDevice.BOND_BONDED) { - Log.w(TAG, "okToConnect: return false, device=" + device + " bondState=" - + bondState); + Log.w( + TAG, + "okToConnect: return false, device=" + device + " bondState=" + bondState); return false; } } diff --git a/android/app/src/com/android/bluetooth/hid/HidHostServiceBinder.java b/android/app/src/com/android/bluetooth/hid/HidHostServiceBinder.java new file mode 100644 index 0000000000..3295c83f01 --- /dev/null +++ b/android/app/src/com/android/bluetooth/hid/HidHostServiceBinder.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.hid; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IBluetoothHidHost; +import android.content.AttributionSource; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +class HidHostServiceBinder extends IBluetoothHidHost.Stub implements IProfileServiceBinder { + private static final String TAG = HidHostServiceBinder.class.getSimpleName(); + + private HidHostService mService; + + HidHostServiceBinder(HidHostService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private HidHostService getService(AttributionSource source) { + HidHostService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + return service; + } + + @Override + public boolean connect(BluetoothDevice device, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.connect(device); + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.disconnect(device); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + return getDevicesMatchingConnectionStates(new int[] {STATE_CONNECTED}, source); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionPolicy(device); + } + + @Override + public boolean setPreferredTransport( + BluetoothDevice device, int transport, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setPreferredTransport(device, transport); + } + + @Override + public int getPreferredTransport(BluetoothDevice device, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return BluetoothDevice.TRANSPORT_AUTO; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getPreferredTransport(device); + } + + /* The following APIs regarding test app for compliance */ + @Override + public boolean getProtocolMode(BluetoothDevice device, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + return service.getProtocolMode(device); + } + + @Override + public boolean virtualUnplug(BluetoothDevice device, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + return service.virtualUnplug(device); + } + + @Override + public boolean setProtocolMode( + BluetoothDevice device, int protocolMode, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + return service.setProtocolMode(device, protocolMode); + } + + @Override + public boolean getReport( + BluetoothDevice device, + byte reportType, + byte reportId, + int bufferSize, + AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + return service.getReport(device, reportType, reportId, bufferSize); + } + + @Override + public boolean setReport( + BluetoothDevice device, byte reportType, String report, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + return service.setReport(device, reportType, report); + } + + @Override + public boolean sendData(BluetoothDevice device, String report, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + return service.sendData(device, report); + } + + @Override + public boolean setIdleTime(BluetoothDevice device, byte idleTime, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + return service.setIdleTime(device, idleTime); + } + + @Override + public boolean getIdleTime(BluetoothDevice device, AttributionSource source) { + HidHostService service = getService(source); + if (service == null) { + return false; + } + return service.getIdleTime(device); + } +} 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 cebf4270e5..4f0d215e5b 100644 --- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java @@ -27,6 +27,7 @@ import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; import static android.bluetooth.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID; import static com.android.bluetooth.bass_client.BassConstants.INVALID_BROADCAST_ID; +import static com.android.bluetooth.flags.Flags.doNotHardcodeTmapRoleMask; import static com.android.bluetooth.flags.Flags.leaudioBigDependsOnAudioState; import static com.android.bluetooth.flags.Flags.leaudioBroadcastApiManagePrimaryGroup; import static com.android.bluetooth.flags.Flags.leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator; @@ -35,7 +36,6 @@ import static com.android.modules.utils.build.SdkLevel.isAtLeastU; import static java.util.Objects.requireNonNull; -import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.bluetooth.BluetoothAdapter; @@ -60,7 +60,6 @@ import android.bluetooth.le.IScannerCallback; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; -import android.content.AttributionSource; import android.content.Context; import android.content.Intent; import android.media.AudioDeviceCallback; @@ -261,24 +260,49 @@ public class LeAudioService extends ProfileService { mStateMachinesThread.start(); // Initialize Broadcast native interface - if ((mAdapterService.getSupportedProfilesBitMask() - & (1 << BluetoothProfile.LE_AUDIO_BROADCAST)) - != 0) { - Log.i(TAG, "Init Le Audio broadcaster"); - LeAudioBroadcasterNativeInterface broadcastNativeInterface = - requireNonNull(LeAudioBroadcasterNativeInterface.getInstance()); - broadcastNativeInterface.init(); - mLeAudioBroadcasterNativeInterface = Optional.of(broadcastNativeInterface); - mTmapRoleMask = - LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG - | LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS - | LeAudioTmapGattServer.TMAP_ROLE_FLAG_BMS; + if (doNotHardcodeTmapRoleMask()) { + int mask = 0; + if (isProfileSupported(BluetoothProfile.LE_CALL_CONTROL)) { + // Table 3.5 of TMAP v1.0: CCP Server is mandatory for the TMAP CG role. + mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG; + } + if (isProfileSupported(BluetoothProfile.MCP_SERVER)) { + // Table 3.5 of TMAP v1.0: MCP Server is mandatory for the TMAP UMS role. + mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS; + } + if (isProfileSupported(BluetoothProfile.LE_AUDIO_BROADCAST)) { + Log.i(TAG, "Init Le Audio broadcaster"); + LeAudioBroadcasterNativeInterface broadcastNativeInterface = + requireNonNull(LeAudioBroadcasterNativeInterface.getInstance()); + broadcastNativeInterface.init(); + mLeAudioBroadcasterNativeInterface = Optional.of(broadcastNativeInterface); + + mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_BMS; + } else { + mLeAudioBroadcasterNativeInterface = Optional.empty(); + Log.w(TAG, "Le Audio Broadcasts not supported."); + } + mTmapRoleMask = mask; } else { - mTmapRoleMask = - LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG - | LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS; - mLeAudioBroadcasterNativeInterface = Optional.empty(); - Log.w(TAG, "Le Audio Broadcasts not supported."); + if ((mAdapterService.getSupportedProfilesBitMask() + & (1 << BluetoothProfile.LE_AUDIO_BROADCAST)) + != 0) { + Log.i(TAG, "Init Le Audio broadcaster"); + LeAudioBroadcasterNativeInterface broadcastNativeInterface = + requireNonNull(LeAudioBroadcasterNativeInterface.getInstance()); + broadcastNativeInterface.init(); + mLeAudioBroadcasterNativeInterface = Optional.of(broadcastNativeInterface); + mTmapRoleMask = + LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG + | LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS + | LeAudioTmapGattServer.TMAP_ROLE_FLAG_BMS; + } else { + mTmapRoleMask = + LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG + | LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS; + mLeAudioBroadcasterNativeInterface = Optional.empty(); + Log.w(TAG, "Le Audio Broadcasts not supported."); + } } mTmapStarted = registerTmap(); @@ -302,6 +326,15 @@ public class LeAudioService extends ProfileService { } } + private boolean isProfileSupported(int profile) { + return (mAdapterService.getSupportedProfilesBitMask() & (1 << profile)) != 0; + } + + @VisibleForTesting + int getTmapRoleMask() { + return mTmapRoleMask; + } + private class LeAudioGroupDescriptor { LeAudioGroupDescriptor(int groupId, boolean isInbandRingtoneEnabled) { mGroupId = groupId; @@ -586,7 +619,7 @@ public class LeAudioService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new BluetoothLeAudioBinder(this); + return new LeAudioServiceBinder(this); } public static boolean isEnabled() { @@ -770,12 +803,12 @@ public class LeAudioService extends ProfileService { mLeAudioBroadcasterNativeInterface.ifPresent(i -> i.cleanup()); - try { - mStateMachinesThread.quitSafely(); - mStateMachinesThread.join(SM_THREAD_JOIN_TIMEOUT_MS); - } catch (InterruptedException e) { - // Do not rethrow as we are shutting down anyway - } + try { + mStateMachinesThread.quitSafely(); + mStateMachinesThread.join(SM_THREAD_JOIN_TIMEOUT_MS); + } catch (InterruptedException e) { + // Do not rethrow as we are shutting down anyway + } mAudioManager.unregisterAudioDeviceCallback(mAudioManagerAudioDeviceCallback); @@ -1799,8 +1832,10 @@ public class LeAudioService extends ProfileService { if (device != null && mActiveAudioInDevice != null) { LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(mActiveAudioInDevice); if (deviceDescriptor == null) { - Log.e(TAG, "updateActiveInDevice: No valid descriptor for device: " - + mActiveAudioInDevice); + Log.e( + TAG, + "updateActiveInDevice: No valid descriptor for device: " + + mActiveAudioInDevice); return false; } @@ -1865,8 +1900,10 @@ public class LeAudioService extends ProfileService { if (device != null && mActiveAudioOutDevice != null) { LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(mActiveAudioOutDevice); if (deviceDescriptor == null) { - Log.e(TAG, "updateActiveOutDevice: No valid descriptor for device: " - + mActiveAudioOutDevice); + Log.e( + TAG, + "updateActiveOutDevice: No valid descriptor for device: " + + mActiveAudioOutDevice); return false; } @@ -2094,9 +2131,7 @@ public class LeAudioService extends ProfileService { Log.d(TAG, "Scanner is not running (mScannerId=" + mScannerId + ")"); return; } - mAdapterService - .getBluetoothScanController() - .stopScanInternal(mScannerId); + mAdapterService.getBluetoothScanController().stopScanInternal(mScannerId); mAdapterService.getBluetoothScanController().unregisterScannerInternal(mScannerId); mScannerId = SCANNER_NOT_INITIALIZED; @@ -3191,8 +3226,10 @@ public class LeAudioService extends ProfileService { boolean ringtoneContextAvailable = false; if (groupDescriptor.mAvailableContexts != null) { - ringtoneContextAvailable = ((groupDescriptor.mAvailableContexts & - BluetoothLeAudio.CONTEXT_TYPE_RINGTONE) != 0); + ringtoneContextAvailable = + ((groupDescriptor.mAvailableContexts + & BluetoothLeAudio.CONTEXT_TYPE_RINGTONE) + != 0); } /* Enables in-band ringtone only for the currently active device or @@ -3689,9 +3726,7 @@ public class LeAudioService extends ProfileService { } else if (isInitial) { Log.i( TAG, - " New group " - + groupId - + " with no context types available"); + " New group " + groupId + " with no context types available"); descriptor.mInactivatedDueToContextType = true; } return; @@ -3759,9 +3794,7 @@ public class LeAudioService extends ProfileService { { LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId); if (descriptor == null) { - Log.e( - TAG, - "deviceDisconnected: no descriptors for group: " + groupId); + Log.e(TAG, "deviceDisconnected: no descriptors for group: " + groupId); return; } @@ -4314,7 +4347,8 @@ public class LeAudioService extends ProfileService { if (getConnectedPeerDevices(groupId).isEmpty()) { descriptor.mIsConnected = false; descriptor.mAutoActiveModeEnabled = true; - descriptor.mAvailableContexts = Flags.leaudioUnicastNoAvailableContexts() ? null : 0; + descriptor.mAvailableContexts = + Flags.leaudioUnicastNoAvailableContexts() ? null : 0; if (descriptor.isActive()) { /* Notify Native layer */ removeActiveDevice(hasFallbackDevice); @@ -5489,12 +5523,15 @@ public class LeAudioService extends ProfileService { * device should be removed from active devices. */ int newDirection = AUDIO_DIRECTION_NONE; - int oldDirection = oldFallbackGroupDescriptor != null - ? oldFallbackGroupDescriptor.mDirection : AUDIO_DIRECTION_NONE; + int oldDirection = + oldFallbackGroupDescriptor != null + ? oldFallbackGroupDescriptor.mDirection + : AUDIO_DIRECTION_NONE; boolean notifyAndUpdateInactiveOutDeviceOnly = false; - boolean hasFallbackDeviceWhenGettingInactive = oldFallbackGroupDescriptor != null - ? oldFallbackGroupDescriptor.mHasFallbackDeviceWhenGettingInactive - : false; + boolean hasFallbackDeviceWhenGettingInactive = + oldFallbackGroupDescriptor != null + ? oldFallbackGroupDescriptor.mHasFallbackDeviceWhenGettingInactive + : false; if (groupId != LE_AUDIO_GROUP_ID_INVALID) { newDirection = AUDIO_DIRECTION_INPUT_BIT; notifyAndUpdateInactiveOutDeviceOnly = true; @@ -5688,525 +5725,6 @@ public class LeAudioService extends ProfileService { } } - /** Binder object: must be a static class or memory leak may occur */ - @VisibleForTesting - static class BluetoothLeAudioBinder extends IBluetoothLeAudio.Stub - implements IProfileServiceBinder { - private LeAudioService mService; - - BluetoothLeAudioBinder(LeAudioService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private LeAudioService getServiceAndEnforceConnect(AttributionSource source) { - requireNonNull(source); - // Cache mService because it can change while getService is called - LeAudioService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - return service; - } - - private LeAudioService getService() { - // Cache mService because it can change while getService is called - LeAudioService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG)) { - return null; - } - return service; - } - - @Override - public boolean connect(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - return service.connect(device); - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - return service.disconnect(device); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getConnectedDevices(); - } - - @Override - public BluetoothDevice getConnectedGroupLeadDevice(int groupId, AttributionSource source) { - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return null; - } - - return service.getConnectedGroupLeadDevice(groupId); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } - - @Override - public boolean setActiveDevice(BluetoothDevice device, AttributionSource source) { - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - if (device == null) { - return service.removeActiveDevice(true); - } else { - return service.setActiveDevice(device); - } - } - - @Override - public List<BluetoothDevice> getActiveDevices(AttributionSource source) { - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getActiveDevices(); - } - - @Override - public int getAudioLocation(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return BluetoothLeAudio.AUDIO_LOCATION_INVALID; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getAudioLocation(device); - } - - @Override - public boolean isInbandRingtoneEnabled(AttributionSource source, int groupId) { - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.isInbandRingtoneEnabled(groupId); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getConnectionPolicy(device); - } - - @Override - public void setCcidInformation( - ParcelUuid userUuid, int ccid, int contextType, AttributionSource source) { - requireNonNull(userUuid); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.setCcidInformation(userUuid, ccid, contextType); - } - - @Override - public int getGroupId(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return LE_AUDIO_GROUP_ID_INVALID; - } - - return service.getGroupId(device); - } - - @Override - public boolean groupAddNode(int groupId, BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.groupAddNode(groupId, device); - } - - @Override - public void setInCall(boolean inCall, AttributionSource source) { - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.setInCall(inCall); - } - - @Override - public void setInactiveForHfpHandover( - BluetoothDevice hfpHandoverDevice, AttributionSource source) { - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.setInactiveForHfpHandover(hfpHandoverDevice); - } - - @Override - public boolean groupRemoveNode( - int groupId, BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.groupRemoveNode(groupId, device); - } - - @Override - public void setVolume(int volume, AttributionSource source) { - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.setVolume(volume); - } - - @Override - public void registerCallback(IBluetoothLeAudioCallback callback, AttributionSource source) { - requireNonNull(callback); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.registerCallback(callback); - } - - @Override - public void unregisterCallback( - IBluetoothLeAudioCallback callback, AttributionSource source) { - requireNonNull(callback); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - service.unregisterCallback(callback); - } - - @Override - public void registerLeBroadcastCallback( - IBluetoothLeBroadcastCallback callback, AttributionSource source) { - requireNonNull(callback); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.registerLeBroadcastCallback(callback); - } - - @Override - public void unregisterLeBroadcastCallback( - IBluetoothLeBroadcastCallback callback, AttributionSource source) { - requireNonNull(callback); - requireNonNull(source); - - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.unregisterLeBroadcastCallback(callback); - } - - @Override - public void startBroadcast( - BluetoothLeBroadcastSettings broadcastSettings, AttributionSource source) { - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.createBroadcast(broadcastSettings); - } - - @Override - public void stopBroadcast(int broadcastId, AttributionSource source) { - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.stopBroadcast(broadcastId); - } - - @Override - public void updateBroadcast( - int broadcastId, - BluetoothLeBroadcastSettings broadcastSettings, - AttributionSource source) { - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.updateBroadcast(broadcastId, broadcastSettings); - } - - @Override - public boolean isPlaying(int broadcastId, AttributionSource source) { - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.isPlaying(broadcastId); - } - - @Override - public List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata( - AttributionSource source) { - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return Collections.emptyList(); - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getAllBroadcastMetadata(); - } - - @Override - public int getMaximumNumberOfBroadcasts() { - LeAudioService service = getService(); - if (service == null) { - return 0; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getMaximumNumberOfBroadcasts(); - } - - @Override - public int getMaximumStreamsPerBroadcast() { - LeAudioService service = getService(); - if (service == null) { - return 0; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getMaximumStreamsPerBroadcast(); - } - - @Override - public int getMaximumSubgroupsPerBroadcast() { - LeAudioService service = getService(); - if (service == null) { - return 0; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getMaximumSubgroupsPerBroadcast(); - } - - @Override - public BluetoothLeAudioCodecStatus getCodecStatus(int groupId, AttributionSource source) { - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return null; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getCodecStatus(groupId); - } - - @Override - public void setCodecConfigPreference( - int groupId, - BluetoothLeAudioCodecConfig inputCodecConfig, - BluetoothLeAudioCodecConfig outputCodecConfig, - AttributionSource source) { - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.setCodecConfigPreference(groupId, inputCodecConfig, outputCodecConfig); - } - - @Override - public void setBroadcastToUnicastFallbackGroup(int groupId, AttributionSource source) { - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.setBroadcastToUnicastFallbackGroup(groupId); - } - - @Override - public int getBroadcastToUnicastFallbackGroup(AttributionSource source) { - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return LE_AUDIO_GROUP_ID_INVALID; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getBroadcastToUnicastFallbackGroup(); - } - - @Override - public boolean isBroadcastActive(AttributionSource source) { - LeAudioService service = getServiceAndEnforceConnect(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.isBroadcastActive(); - } - } - @Override public void dump(StringBuilder sb) { super.dump(sb); diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioServiceBinder.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioServiceBinder.java new file mode 100644 index 0000000000..e774c8fe33 --- /dev/null +++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioServiceBinder.java @@ -0,0 +1,548 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.le_audio; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; +import static android.bluetooth.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID; + +import static java.util.Objects.requireNonNull; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeAudio; +import android.bluetooth.BluetoothLeAudioCodecConfig; +import android.bluetooth.BluetoothLeAudioCodecStatus; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastSettings; +import android.bluetooth.IBluetoothLeAudio; +import android.bluetooth.IBluetoothLeAudioCallback; +import android.bluetooth.IBluetoothLeBroadcastCallback; +import android.content.AttributionSource; +import android.os.ParcelUuid; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +class LeAudioServiceBinder extends IBluetoothLeAudio.Stub implements IProfileServiceBinder { + private static final String TAG = LeAudioServiceBinder.class.getSimpleName(); + + private LeAudioService mService; + + LeAudioServiceBinder(LeAudioService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + private LeAudioService getService() { + LeAudioService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG)) { + return null; + } + return service; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private LeAudioService getServiceAndEnforceConnect(AttributionSource source) { + requireNonNull(source); + LeAudioService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + return service; + } + + @Override + public boolean connect(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + return service.connect(device); + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + return service.disconnect(device); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public BluetoothDevice getConnectedGroupLeadDevice(int groupId, AttributionSource source) { + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return null; + } + return service.getConnectedGroupLeadDevice(groupId); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public boolean setActiveDevice(BluetoothDevice device, AttributionSource source) { + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + if (device == null) { + return service.removeActiveDevice(true); + } else { + return service.setActiveDevice(device); + } + } + + @Override + public List<BluetoothDevice> getActiveDevices(AttributionSource source) { + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getActiveDevices(); + } + + @Override + public int getAudioLocation(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return BluetoothLeAudio.AUDIO_LOCATION_INVALID; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getAudioLocation(device); + } + + @Override + public boolean isInbandRingtoneEnabled(AttributionSource source, int groupId) { + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.isInbandRingtoneEnabled(groupId); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionPolicy(device); + } + + @Override + public void setCcidInformation( + ParcelUuid userUuid, int ccid, int contextType, AttributionSource source) { + requireNonNull(userUuid); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setCcidInformation(userUuid, ccid, contextType); + } + + @Override + public int getGroupId(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return LE_AUDIO_GROUP_ID_INVALID; + } + return service.getGroupId(device); + } + + @Override + public boolean groupAddNode(int groupId, BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.groupAddNode(groupId, device); + } + + @Override + public void setInCall(boolean inCall, AttributionSource source) { + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setInCall(inCall); + } + + @Override + public void setInactiveForHfpHandover( + BluetoothDevice hfpHandoverDevice, AttributionSource source) { + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setInactiveForHfpHandover(hfpHandoverDevice); + } + + @Override + public boolean groupRemoveNode(int groupId, BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.groupRemoveNode(groupId, device); + } + + @Override + public void setVolume(int volume, AttributionSource source) { + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setVolume(volume); + } + + @Override + public void registerCallback(IBluetoothLeAudioCallback callback, AttributionSource source) { + requireNonNull(callback); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.registerCallback(callback); + } + + @Override + public void unregisterCallback(IBluetoothLeAudioCallback callback, AttributionSource source) { + requireNonNull(callback); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.unregisterCallback(callback); + } + + @Override + public void registerLeBroadcastCallback( + IBluetoothLeBroadcastCallback callback, AttributionSource source) { + requireNonNull(callback); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.registerLeBroadcastCallback(callback); + } + + @Override + public void unregisterLeBroadcastCallback( + IBluetoothLeBroadcastCallback callback, AttributionSource source) { + requireNonNull(callback); + requireNonNull(source); + + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.unregisterLeBroadcastCallback(callback); + } + + @Override + public void startBroadcast( + BluetoothLeBroadcastSettings broadcastSettings, AttributionSource source) { + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.createBroadcast(broadcastSettings); + } + + @Override + public void stopBroadcast(int broadcastId, AttributionSource source) { + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.stopBroadcast(broadcastId); + } + + @Override + public void updateBroadcast( + int broadcastId, + BluetoothLeBroadcastSettings broadcastSettings, + AttributionSource source) { + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.updateBroadcast(broadcastId, broadcastSettings); + } + + @Override + public boolean isPlaying(int broadcastId, AttributionSource source) { + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.isPlaying(broadcastId); + } + + @Override + public List<BluetoothLeBroadcastMetadata> getAllBroadcastMetadata(AttributionSource source) { + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return Collections.emptyList(); + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getAllBroadcastMetadata(); + } + + @Override + public int getMaximumNumberOfBroadcasts() { + LeAudioService service = getService(); + if (service == null) { + return 0; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getMaximumNumberOfBroadcasts(); + } + + @Override + public int getMaximumStreamsPerBroadcast() { + LeAudioService service = getService(); + if (service == null) { + return 0; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getMaximumStreamsPerBroadcast(); + } + + @Override + public int getMaximumSubgroupsPerBroadcast() { + LeAudioService service = getService(); + if (service == null) { + return 0; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getMaximumSubgroupsPerBroadcast(); + } + + @Override + public BluetoothLeAudioCodecStatus getCodecStatus(int groupId, AttributionSource source) { + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getCodecStatus(groupId); + } + + @Override + public void setCodecConfigPreference( + int groupId, + BluetoothLeAudioCodecConfig inputCodecConfig, + BluetoothLeAudioCodecConfig outputCodecConfig, + AttributionSource source) { + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setCodecConfigPreference(groupId, inputCodecConfig, outputCodecConfig); + } + + @Override + public void setBroadcastToUnicastFallbackGroup(int groupId, AttributionSource source) { + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setBroadcastToUnicastFallbackGroup(groupId); + } + + @Override + public int getBroadcastToUnicastFallbackGroup(AttributionSource source) { + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return LE_AUDIO_GROUP_ID_INVALID; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getBroadcastToUnicastFallbackGroup(); + } + + @Override + public boolean isBroadcastActive(AttributionSource source) { + LeAudioService service = getServiceAndEnforceConnect(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.isBroadcastActive(); + } +} diff --git a/android/app/src/com/android/bluetooth/le_audio/OWNERS b/android/app/src/com/android/bluetooth/le_audio/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/app/src/com/android/bluetooth/le_audio/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/app/src/com/android/bluetooth/le_scan/AppScanStats.java b/android/app/src/com/android/bluetooth/le_scan/AppScanStats.java index 4bead29e8c..07d7209b40 100644 --- a/android/app/src/com/android/bluetooth/le_scan/AppScanStats.java +++ b/android/app/src/com/android/bluetooth/le_scan/AppScanStats.java @@ -34,7 +34,6 @@ import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.Utils.TimeProvider; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.MetricsLogger; -import com.android.bluetooth.flags.Flags; import com.android.bluetooth.util.WorkSourceUtil; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -72,6 +71,7 @@ class AppScanStats { static boolean sIsRadioStarted = false; static boolean sIsScreenOn = false; static int sRadioScanAppImportance = IMPORTANCE_CACHED; + @Nullable static String sRadioScanAttributionTag; @GuardedBy("sLock") static long sRadioStartTime = 0; @@ -133,6 +133,10 @@ class AppScanStats { this.appImportanceOnStart = appImportanceOnStart; this.filterString = new StringBuilder(); } + + private String getAttributionTag() { + return attributionTag != null ? attributionTag : ""; + } } private final List<LastScan> mLastScans = new ArrayList<>(); @@ -190,6 +194,7 @@ class AppScanStats { mTimeProvider = requireNonNull(timeProvider); } + @Nullable private synchronized LastScan getScanFromScannerId(int scannerId) { return mOngoingScans.get(scannerId); } @@ -389,23 +394,22 @@ class AppScanStats { private void recordScanAppCountMetricsStart(LastScan scan) { MetricsLogger logger = MetricsLogger.getInstance(); logger.cacheCount(BluetoothProtoEnums.LE_SCAN_COUNT_TOTAL_ENABLE, 1); - if (Flags.bleScanAdvMetricsRedesign()) { - logger.logAppScanStateChanged( - mWorkSourceUtil.getUids(), - mWorkSourceUtil.getTags(), - true /* enabled */, - scan.isFilterScan, - scan.isCallbackScan, - convertScanCallbackType(scan.scanCallbackType), - convertScanType(scan), - convertScanMode(scan.scanMode), - scan.reportDelayMillis, - 0 /* app_scan_duration_ms */, - mOngoingScans.size(), - sIsScreenOn, - isAppDead, - mAppImportance); - } + logger.logAppScanStateChanged( + mWorkSourceUtil.getUids(), + mWorkSourceUtil.getTags(), + true /* enabled */, + scan.isFilterScan, + scan.isCallbackScan, + convertScanCallbackType(scan.scanCallbackType), + convertScanType(scan), + convertScanMode(scan.scanMode), + scan.reportDelayMillis, + 0 /* app_scan_duration_ms */, + mOngoingScans.size(), + sIsScreenOn, + isAppDead, + mAppImportance, + scan.getAttributionTag()); if (scan.isAutoBatchScan) { logger.cacheCount(BluetoothProtoEnums.LE_SCAN_COUNT_AUTO_BATCH_ENABLE, 1); } else if (scan.isBatchScan) { @@ -422,23 +426,22 @@ class AppScanStats { private void recordScanAppCountMetricsStop(LastScan scan) { MetricsLogger logger = MetricsLogger.getInstance(); logger.cacheCount(BluetoothProtoEnums.LE_SCAN_COUNT_TOTAL_DISABLE, 1); - if (Flags.bleScanAdvMetricsRedesign()) { - logger.logAppScanStateChanged( - mWorkSourceUtil.getUids(), - mWorkSourceUtil.getTags(), - false /* enabled */, - scan.isFilterScan, - scan.isCallbackScan, - convertScanCallbackType(scan.scanCallbackType), - convertScanType(scan), - convertScanMode(scan.scanMode), - scan.reportDelayMillis, - scan.duration, - mOngoingScans.size(), - sIsScreenOn, - isAppDead, - mAppImportance); - } + logger.logAppScanStateChanged( + mWorkSourceUtil.getUids(), + mWorkSourceUtil.getTags(), + false /* enabled */, + scan.isFilterScan, + scan.isCallbackScan, + convertScanCallbackType(scan.scanCallbackType), + convertScanType(scan), + convertScanMode(scan.scanMode), + scan.reportDelayMillis, + scan.duration, + mOngoingScans.size(), + sIsScreenOn, + isAppDead, + mAppImportance, + scan.getAttributionTag()); if (scan.isAutoBatchScan) { logger.cacheCount(BluetoothProtoEnums.LE_SCAN_COUNT_AUTO_BATCH_DISABLE, 1); } else if (scan.isBatchScan) { @@ -515,46 +518,43 @@ class AppScanStats { } synchronized void recordScanTimeoutCountMetrics(int scannerId, long scanTimeoutMillis) { - if (Flags.bleScanAdvMetricsRedesign()) { - BluetoothStatsLog.write( - BluetoothStatsLog.LE_SCAN_ABUSED, - mWorkSourceUtil.getUids(), - mWorkSourceUtil.getTags(), - convertScanType(getScanFromScannerId(scannerId)), - BluetoothStatsLog.LE_SCAN_ABUSED__LE_SCAN_ABUSE_REASON__REASON_SCAN_TIMEOUT, - scanTimeoutMillis); - } + BluetoothStatsLog.write( + BluetoothStatsLog.LE_SCAN_ABUSED, + mWorkSourceUtil.getUids(), + mWorkSourceUtil.getTags(), + convertScanType(getScanFromScannerId(scannerId)), + BluetoothStatsLog.LE_SCAN_ABUSED__LE_SCAN_ABUSE_REASON__REASON_SCAN_TIMEOUT, + scanTimeoutMillis, + getAttributionTagFromScannerId(scannerId)); MetricsLogger.getInstance() .cacheCount(BluetoothProtoEnums.LE_SCAN_ABUSE_COUNT_SCAN_TIMEOUT, 1); } synchronized void recordHwFilterNotAvailableCountMetrics( int scannerId, long numOfFilterSupported) { - if (Flags.bleScanAdvMetricsRedesign()) { - BluetoothStatsLog.write( - BluetoothStatsLog.LE_SCAN_ABUSED, - mWorkSourceUtil.getUids(), - mWorkSourceUtil.getTags(), - convertScanType(getScanFromScannerId(scannerId)), - BluetoothStatsLog.LE_SCAN_ABUSED__LE_SCAN_ABUSE_REASON__REASON_HW_FILTER_NA, - numOfFilterSupported); - } + BluetoothStatsLog.write( + BluetoothStatsLog.LE_SCAN_ABUSED, + mWorkSourceUtil.getUids(), + mWorkSourceUtil.getTags(), + convertScanType(getScanFromScannerId(scannerId)), + BluetoothStatsLog.LE_SCAN_ABUSED__LE_SCAN_ABUSE_REASON__REASON_HW_FILTER_NA, + numOfFilterSupported, + getAttributionTagFromScannerId(scannerId)); MetricsLogger.getInstance() .cacheCount(BluetoothProtoEnums.LE_SCAN_ABUSE_COUNT_HW_FILTER_NOT_AVAILABLE, 1); } synchronized void recordTrackingHwFilterNotAvailableCountMetrics( int scannerId, long numOfTrackableAdv) { - if (Flags.bleScanAdvMetricsRedesign()) { - BluetoothStatsLog.write( - BluetoothStatsLog.LE_SCAN_ABUSED, - mWorkSourceUtil.getUids(), - mWorkSourceUtil.getTags(), - convertScanType(getScanFromScannerId(scannerId)), - BluetoothStatsLog - .LE_SCAN_ABUSED__LE_SCAN_ABUSE_REASON__REASON_TRACKING_HW_FILTER_NA, - numOfTrackableAdv); - } + BluetoothStatsLog.write( + BluetoothStatsLog.LE_SCAN_ABUSED, + mWorkSourceUtil.getUids(), + mWorkSourceUtil.getTags(), + convertScanType(getScanFromScannerId(scannerId)), + BluetoothStatsLog + .LE_SCAN_ABUSED__LE_SCAN_ABUSE_REASON__REASON_TRACKING_HW_FILTER_NA, + numOfTrackableAdv, + getAttributionTagFromScannerId(scannerId)); MetricsLogger.getInstance() .cacheCount( BluetoothProtoEnums.LE_SCAN_ABUSE_COUNT_TRACKING_HW_FILTER_NOT_AVAILABLE, @@ -586,6 +586,7 @@ class AppScanStats { sRadioScanIntervalMs = scanIntervalMs; sIsRadioStarted = true; sRadioScanAppImportance = stats.mAppImportance; + sRadioScanAttributionTag = stats.getAttributionTagFromScannerId(scannerId); } return true; } @@ -596,10 +597,6 @@ class AppScanStats { return false; } recordScanRadioDurationMetrics(timeProvider); - if (!Flags.bleScanAdvMetricsRedesign()) { - sRadioStartTime = 0; - sIsRadioStarted = false; - } } return true; } @@ -615,20 +612,19 @@ class AppScanStats { double scanWeight = getScanWeight(sRadioScanMode) * 0.01; long weightedDuration = (long) (radioScanDuration * scanWeight); - if (Flags.bleScanAdvMetricsRedesign()) { - logger.logRadioScanStopped( - getRadioScanUids(), - getRadioScanTags(), - sRadioScanType, - convertScanMode(sRadioScanMode), - sRadioScanIntervalMs, - sRadioScanWindowMs, - sIsScreenOn, - radioScanDuration, - sRadioScanAppImportance); - sRadioStartTime = 0; - sIsRadioStarted = false; - } + logger.logRadioScanStopped( + getRadioScanUids(), + getRadioScanTags(), + sRadioScanType, + convertScanMode(sRadioScanMode), + sRadioScanIntervalMs, + sRadioScanWindowMs, + sIsScreenOn, + radioScanDuration, + sRadioScanAppImportance, + getRadioScanAttributionTag()); + sRadioStartTime = 0; + sIsRadioStarted = false; if (weightedDuration > 0) { logger.cacheCount(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR, weightedDuration); if (sIsScreenOn) { @@ -659,6 +655,12 @@ class AppScanStats { } } + private static String getRadioScanAttributionTag() { + synchronized (sLock) { + return sRadioScanAttributionTag != null ? sRadioScanAttributionTag : ""; + } + } + @GuardedBy("sLock") private static void recordScreenOnOffMetrics(boolean isScreenOn) { if (isScreenOn) { @@ -692,15 +694,14 @@ class AppScanStats { if (!sIsRadioStarted) { return; } - if (Flags.bleScanAdvMetricsRedesign()) { - BluetoothStatsLog.write( - BluetoothStatsLog.LE_SCAN_RESULT_RECEIVED, - getRadioScanUids(), - getRadioScanTags(), - 1 /* num_results */, - BluetoothStatsLog.LE_SCAN_RESULT_RECEIVED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR, - sIsScreenOn); - } + BluetoothStatsLog.write( + BluetoothStatsLog.LE_SCAN_RESULT_RECEIVED, + getRadioScanUids(), + getRadioScanTags(), + 1 /* num_results */, + BluetoothStatsLog.LE_SCAN_RESULT_RECEIVED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR, + sIsScreenOn, + getRadioScanAttributionTag()); MetricsLogger logger = MetricsLogger.getInstance(); logger.cacheCount(BluetoothProtoEnums.LE_SCAN_RESULTS_COUNT_REGULAR, 1); if (sIsScreenOn) { @@ -716,15 +717,14 @@ class AppScanStats { synchronized (sLock) { isScreenOn = sIsScreenOn; } - if (Flags.bleScanAdvMetricsRedesign()) { - BluetoothStatsLog.write( - BluetoothStatsLog.LE_SCAN_RESULT_RECEIVED, - getRadioScanUids(), - getRadioScanTags(), - numRecords, - BluetoothStatsLog.LE_SCAN_RESULT_RECEIVED__LE_SCAN_TYPE__SCAN_TYPE_BATCH, - sIsScreenOn); - } + BluetoothStatsLog.write( + BluetoothStatsLog.LE_SCAN_RESULT_RECEIVED, + getRadioScanUids(), + getRadioScanTags(), + numRecords, + BluetoothStatsLog.LE_SCAN_RESULT_RECEIVED__LE_SCAN_TYPE__SCAN_TYPE_BATCH, + sIsScreenOn, + getRadioScanAttributionTag()); MetricsLogger logger = MetricsLogger.getInstance(); logger.cacheCount(BluetoothProtoEnums.LE_SCAN_RESULTS_COUNT_BATCH_BUNDLE, 1); logger.cacheCount(BluetoothProtoEnums.LE_SCAN_RESULTS_COUNT_BATCH, numRecords); @@ -829,6 +829,11 @@ class AppScanStats { < LARGE_SCAN_TIME_GAP_MS); } + private String getAttributionTagFromScannerId(int scannerId) { + LastScan scan = getScanFromScannerId(scannerId); + return scan == null ? "" : scan.getAttributionTag(); + } + private static String filterToStringWithoutNullParam(ScanFilter filter) { StringBuilder filterString = new StringBuilder("BluetoothLeScanFilter ["); if (filter.getDeviceName() != null) { diff --git a/android/app/src/com/android/bluetooth/le_scan/ScanController.java b/android/app/src/com/android/bluetooth/le_scan/ScanController.java index 82b8e10dd7..2fc20d8314 100644 --- a/android/app/src/com/android/bluetooth/le_scan/ScanController.java +++ b/android/app/src/com/android/bluetooth/le_scan/ScanController.java @@ -22,6 +22,7 @@ import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.bluetooth.BluetoothUtils.extractBytes; import static com.android.bluetooth.Utils.checkCallerTargetSdk; +import static com.android.bluetooth.Utils.checkScanPermissionForDataDelivery; import static com.android.bluetooth.flags.Flags.leaudioBassScanWithInternalScanController; import static java.util.Objects.requireNonNull; @@ -1082,8 +1083,7 @@ public class ScanController { @RequiresPermission(BLUETOOTH_SCAN) void registerScanner( IScannerCallback callback, WorkSource workSource, AttributionSource source) { - if (!Utils.checkScanPermissionForDataDelivery( - mAdapterService, source, "ScanController registerScanner")) { + if (!checkScanPermissionForDataDelivery(mAdapterService, source, TAG, "registerScanner")) { return; } @@ -1116,8 +1116,8 @@ public class ScanController { @RequiresPermission(BLUETOOTH_SCAN) void unregisterScanner(int scannerId, AttributionSource source) { - if (!Utils.checkScanPermissionForDataDelivery( - mAdapterService, source, "ScanController unregisterScanner")) { + if (!checkScanPermissionForDataDelivery( + mAdapterService, source, TAG, "unregisterScanner")) { return; } @@ -1163,7 +1163,7 @@ public class ScanController { List<ScanFilter> filters, AttributionSource source) { Log.d(TAG, "Start scan with filters"); - if (!Utils.checkScanPermissionForDataDelivery(mAdapterService, source, "Starting scan.")) { + if (!checkScanPermissionForDataDelivery(mAdapterService, source, TAG, "startScan")) { return; } @@ -1255,7 +1255,8 @@ public class ScanController { List<ScanFilter> filters, AttributionSource source) { Log.d(TAG, "Start scan with filters, for PendingIntent"); - if (!Utils.checkScanPermissionForDataDelivery(mAdapterService, source, "Starting scan.")) { + if (!checkScanPermissionForDataDelivery( + mAdapterService, source, TAG, "registerPiAndStartScan")) { return; } @@ -1359,8 +1360,8 @@ public class ScanController { @RequiresPermission(BLUETOOTH_SCAN) void flushPendingBatchResults(int scannerId, AttributionSource source) { - if (!Utils.checkScanPermissionForDataDelivery( - mAdapterService, source, "ScanController flushPendingBatchResults")) { + if (!checkScanPermissionForDataDelivery( + mAdapterService, source, TAG, "flushPendingBatchResults")) { return; } flushPendingBatchResultsInternal(scannerId); @@ -1373,8 +1374,7 @@ public class ScanController { @RequiresPermission(BLUETOOTH_SCAN) void stopScan(int scannerId, AttributionSource source) { - if (!Utils.checkScanPermissionForDataDelivery( - mAdapterService, source, "ScanController stopScan")) { + if (!checkScanPermissionForDataDelivery(mAdapterService, source, TAG, "stopScan")) { return; } stopScanInternal(scannerId); @@ -1396,8 +1396,7 @@ public class ScanController { @RequiresPermission(BLUETOOTH_SCAN) void stopScan(PendingIntent intent, AttributionSource source) { - if (!Utils.checkScanPermissionForDataDelivery( - mAdapterService, source, "ScanController stopScan")) { + if (!checkScanPermissionForDataDelivery(mAdapterService, source, TAG, "stopScan")) { return; } stopScanInternal(intent); @@ -1426,8 +1425,7 @@ public class ScanController { int timeout, IPeriodicAdvertisingCallback callback, AttributionSource source) { - if (!Utils.checkScanPermissionForDataDelivery( - mAdapterService, source, "ScanController registerSync")) { + if (!checkScanPermissionForDataDelivery(mAdapterService, source, TAG, "registerSync")) { return; } mPeriodicScanManager.startSync(scanResult, skip, timeout, callback); @@ -1435,8 +1433,7 @@ public class ScanController { @RequiresPermission(BLUETOOTH_SCAN) void unregisterSync(IPeriodicAdvertisingCallback callback, AttributionSource source) { - if (!Utils.checkScanPermissionForDataDelivery( - mAdapterService, source, "ScanController unregisterSync")) { + if (!checkScanPermissionForDataDelivery(mAdapterService, source, TAG, "unregisterSync")) { return; } mPeriodicScanManager.stopSync(callback); @@ -1445,8 +1442,7 @@ public class ScanController { @RequiresPermission(BLUETOOTH_SCAN) void transferSync( BluetoothDevice bda, int serviceData, int syncHandle, AttributionSource source) { - if (!Utils.checkScanPermissionForDataDelivery( - mAdapterService, source, "ScanController transferSync")) { + if (!checkScanPermissionForDataDelivery(mAdapterService, source, TAG, "transferSync")) { return; } mPeriodicScanManager.transferSync(bda, serviceData, syncHandle); @@ -1459,8 +1455,7 @@ public class ScanController { int advHandle, IPeriodicAdvertisingCallback callback, AttributionSource source) { - if (!Utils.checkScanPermissionForDataDelivery( - mAdapterService, source, "ScanController transferSetInfo")) { + if (!checkScanPermissionForDataDelivery(mAdapterService, source, TAG, "transferSetInfo")) { return; } mPeriodicScanManager.transferSetInfo(bda, serviceData, advHandle, callback); @@ -1468,8 +1463,8 @@ public class ScanController { @RequiresPermission(BLUETOOTH_SCAN) int numHwTrackFiltersAvailable(AttributionSource source) { - if (!Utils.checkScanPermissionForDataDelivery( - mAdapterService, source, "ScanController numHwTrackFiltersAvailable")) { + if (!checkScanPermissionForDataDelivery( + mAdapterService, source, TAG, "numHwTrackFiltersAvailable")) { return 0; } return (mAdapterService.getTotalNumOfTrackableAdvertisements() diff --git a/android/app/src/com/android/bluetooth/le_scan/ScanManager.java b/android/app/src/com/android/bluetooth/le_scan/ScanManager.java index cf6ef7d928..e31bd36bbb 100644 --- a/android/app/src/com/android/bluetooth/le_scan/ScanManager.java +++ b/android/app/src/com/android/bluetooth/le_scan/ScanManager.java @@ -1292,18 +1292,6 @@ public class ScanManager { && client.mSettings.getScanMode() != ScanSettings.SCAN_MODE_OPPORTUNISTIC) { Log.d(TAG, "start gattClientScanNative from startRegularScan()"); mNativeInterface.gattClientScan(true); - if (!Flags.bleScanAdvMetricsRedesign()) { - if (client.mStats != null - && !AppScanStats.recordScanRadioStart( - client.mSettings.getScanMode(), - client.mScannerId, - client.mStats, - getScanWindowMillis(client.mSettings), - getScanIntervalMillis(client.mSettings), - mTimeProvider)) { - Log.w(TAG, "Scan radio already started"); - } - } } } diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapService.java b/android/app/src/com/android/bluetooth/map/BluetoothMapService.java index bac8bdc247..b43af84dcc 100644 --- a/android/app/src/com/android/bluetooth/map/BluetoothMapService.java +++ b/android/app/src/com/android/bluetooth/map/BluetoothMapService.java @@ -18,7 +18,6 @@ package com.android.bluetooth.map; import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; -import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; @@ -33,9 +32,7 @@ import android.bluetooth.BluetoothMap; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProtoEnums; import android.bluetooth.BluetoothUuid; -import android.bluetooth.IBluetoothMap; import android.bluetooth.SdpMnsRecord; -import android.content.AttributionSource; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -66,7 +63,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -149,7 +145,6 @@ public class BluetoothMapService extends ProfileService { private static BluetoothMapService sBluetoothMapService; - private static final ParcelUuid[] MAP_UUIDS = { BluetoothUuid.MAP, BluetoothUuid.MNS, }; @@ -705,7 +700,7 @@ public class BluetoothMapService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new BluetoothMapBinder(this); + return new BluetoothMapServiceBinder(this); } /** @@ -1190,227 +1185,6 @@ public class BluetoothMapService extends ProfileService { } } - // Binder object: Must be static class or memory leak may occur - - /** - * This class implements the IBluetoothMap interface - or actually it validates the - * preconditions for calling the actual functionality in the MapService, and calls it. - */ - @VisibleForTesting - static class BluetoothMapBinder extends IBluetoothMap.Stub implements IProfileServiceBinder { - private BluetoothMapService mService; - - BluetoothMapBinder(BluetoothMapService service) { - mService = service; - } - - @Override - public synchronized void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private BluetoothMapService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - BluetoothMapService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - return service; - } - - @Override - public int getState(AttributionSource source) { - Log.v(TAG, "getState()"); - try { - BluetoothMapService service = getService(source); - if (service == null) { - return BluetoothMap.STATE_DISCONNECTED; - } - - return service.getState(); - } catch (RuntimeException e) { - ContentProfileErrorReportUtils.report( - BluetoothProfile.MAP, - BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, - BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, - 16); - throw e; - } - } - - @Override - public BluetoothDevice getClient(AttributionSource source) { - Log.v(TAG, "getClient()"); - try { - BluetoothMapService service = getService(source); - if (service == null) { - Log.v(TAG, "getClient() - no service - returning " + null); - return null; - } - BluetoothDevice client = service.getRemoteDevice(); - Log.v(TAG, "getClient() - returning " + client); - return client; - } catch (RuntimeException e) { - ContentProfileErrorReportUtils.report( - BluetoothProfile.MAP, - BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, - BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, - 17); - throw e; - } - } - - @Override - public boolean isConnected(BluetoothDevice device, AttributionSource source) { - Log.v(TAG, "isConnected()"); - try { - BluetoothMapService service = getService(source); - if (service == null) { - return false; - } - - return service.getConnectionState(device) == STATE_CONNECTED; - } catch (RuntimeException e) { - ContentProfileErrorReportUtils.report( - BluetoothProfile.MAP, - BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, - BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, - 18); - throw e; - } - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - Log.v(TAG, "disconnect()"); - try { - BluetoothMapService service = getService(source); - if (service == null) { - return false; - } - - service.disconnect(device); - return true; - } catch (RuntimeException e) { - ContentProfileErrorReportUtils.report( - BluetoothProfile.MAP, - BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, - BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, - 19); - throw e; - } - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - Log.v(TAG, "getConnectedDevices()"); - try { - BluetoothMapService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getConnectedDevices(); - } catch (RuntimeException e) { - ContentProfileErrorReportUtils.report( - BluetoothProfile.MAP, - BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, - BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, - 20); - throw e; - } - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - Log.v(TAG, "getDevicesMatchingConnectionStates()"); - try { - BluetoothMapService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getDevicesMatchingConnectionStates(states); - } catch (RuntimeException e) { - ContentProfileErrorReportUtils.report( - BluetoothProfile.MAP, - BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, - BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, - 21); - throw e; - } - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - Log.v(TAG, "getConnectionState()"); - try { - BluetoothMapService service = getService(source); - if (service == null) { - return STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } catch (RuntimeException e) { - ContentProfileErrorReportUtils.report( - BluetoothProfile.MAP, - BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, - BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, - 22); - throw e; - } - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - try { - BluetoothMapService service = getService(source); - if (service == null) { - return false; - } - - return service.setConnectionPolicy(device, connectionPolicy); - } catch (RuntimeException e) { - ContentProfileErrorReportUtils.report( - BluetoothProfile.MAP, - BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, - BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, - 23); - throw e; - } - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - try { - BluetoothMapService service = getService(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - return service.getConnectionPolicy(device); - } catch (RuntimeException e) { - ContentProfileErrorReportUtils.report( - BluetoothProfile.MAP, - BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, - BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, - 24); - throw e; - } - } - } - @Override public void dump(StringBuilder sb) { super.dump(sb); diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapServiceBinder.java b/android/app/src/com/android/bluetooth/map/BluetoothMapServiceBinder.java new file mode 100644 index 0000000000..0706bcab6f --- /dev/null +++ b/android/app/src/com/android/bluetooth/map/BluetoothMapServiceBinder.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.map; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothMap; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothProtoEnums; +import android.bluetooth.IBluetoothMap; +import android.content.AttributionSource; +import android.util.Log; + +import com.android.bluetooth.BluetoothStatsLog; +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; +import com.android.bluetooth.content_profiles.ContentProfileErrorReportUtils; + +import java.util.Collections; +import java.util.List; + +/** + * This class implements the IBluetoothMap interface - or actually it validates the preconditions + * for calling the actual functionality in the MapService, and calls it. + */ +class BluetoothMapServiceBinder extends IBluetoothMap.Stub implements IProfileServiceBinder { + private static final String TAG = BluetoothMapServiceBinder.class.getSimpleName(); + + private BluetoothMapService mService; + + BluetoothMapServiceBinder(BluetoothMapService service) { + mService = service; + } + + @Override + public synchronized void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private BluetoothMapService getService(AttributionSource source) { + BluetoothMapService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + return service; + } + + @Override + public int getState(AttributionSource source) { + Log.v(TAG, "getState()"); + try { + BluetoothMapService service = getService(source); + if (service == null) { + return BluetoothMap.STATE_DISCONNECTED; + } + return service.getState(); + } catch (RuntimeException e) { + ContentProfileErrorReportUtils.report( + BluetoothProfile.MAP, + BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, + BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, + 16); + throw e; + } + } + + @Override + public BluetoothDevice getClient(AttributionSource source) { + Log.v(TAG, "getClient()"); + try { + BluetoothMapService service = getService(source); + if (service == null) { + Log.v(TAG, "getClient() - no service - returning " + null); + return null; + } + BluetoothDevice client = service.getRemoteDevice(); + Log.v(TAG, "getClient() - returning " + client); + return client; + } catch (RuntimeException e) { + ContentProfileErrorReportUtils.report( + BluetoothProfile.MAP, + BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, + BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, + 17); + throw e; + } + } + + @Override + public boolean isConnected(BluetoothDevice device, AttributionSource source) { + Log.v(TAG, "isConnected()"); + try { + BluetoothMapService service = getService(source); + if (service == null) { + return false; + } + return service.getConnectionState(device) == STATE_CONNECTED; + } catch (RuntimeException e) { + ContentProfileErrorReportUtils.report( + BluetoothProfile.MAP, + BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, + BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, + 18); + throw e; + } + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + Log.v(TAG, "disconnect()"); + try { + BluetoothMapService service = getService(source); + if (service == null) { + return false; + } + service.disconnect(device); + return true; + } catch (RuntimeException e) { + ContentProfileErrorReportUtils.report( + BluetoothProfile.MAP, + BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, + BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, + 19); + throw e; + } + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + Log.v(TAG, "getConnectedDevices()"); + try { + BluetoothMapService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectedDevices(); + } catch (RuntimeException e) { + ContentProfileErrorReportUtils.report( + BluetoothProfile.MAP, + BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, + BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, + 20); + throw e; + } + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + Log.v(TAG, "getDevicesMatchingConnectionStates()"); + try { + BluetoothMapService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } catch (RuntimeException e) { + ContentProfileErrorReportUtils.report( + BluetoothProfile.MAP, + BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, + BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, + 21); + throw e; + } + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + Log.v(TAG, "getConnectionState()"); + try { + BluetoothMapService service = getService(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } catch (RuntimeException e) { + ContentProfileErrorReportUtils.report( + BluetoothProfile.MAP, + BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, + BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, + 22); + throw e; + } + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + try { + BluetoothMapService service = getService(source); + if (service == null) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } catch (RuntimeException e) { + ContentProfileErrorReportUtils.report( + BluetoothProfile.MAP, + BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, + BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, + 23); + throw e; + } + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + try { + BluetoothMapService service = getService(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + return service.getConnectionPolicy(device); + } catch (RuntimeException e) { + ContentProfileErrorReportUtils.report( + BluetoothProfile.MAP, + BluetoothProtoEnums.BLUETOOTH_MAP_SERVICE, + BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, + 24); + throw e; + } + } +} diff --git a/android/app/src/com/android/bluetooth/map/OWNERS b/android/app/src/com/android/bluetooth/map/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/src/com/android/bluetooth/map/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/src/com/android/bluetooth/mapclient/MapClientService.java b/android/app/src/com/android/bluetooth/mapclient/MapClientService.java index 5e2be59b11..fdecfddf15 100644 --- a/android/app/src/com/android/bluetooth/mapclient/MapClientService.java +++ b/android/app/src/com/android/bluetooth/mapclient/MapClientService.java @@ -16,11 +16,8 @@ package com.android.bluetooth.mapclient; -import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; -import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; import static android.bluetooth.BluetoothProfile.STATE_CONNECTING; import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; @@ -28,16 +25,12 @@ import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNullElseGet; -import android.Manifest; -import android.annotation.RequiresPermission; import android.app.PendingIntent; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; -import android.bluetooth.IBluetoothMapClient; import android.bluetooth.SdpMasRecord; -import android.content.AttributionSource; import android.net.Uri; import android.os.Handler; import android.os.Looper; @@ -46,7 +39,6 @@ import android.os.Parcelable; import android.sysprop.BluetoothProperties; import android.util.Log; -import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.storage.DatabaseManager; @@ -54,7 +46,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -307,7 +298,7 @@ public class MapClientService extends ProfileService { @Override public IProfileServiceBinder initBinder() { - return new Binder(this); + return new MapClientServiceBinder(this); } @Override @@ -408,172 +399,6 @@ public class MapClientService extends ProfileService { } } - // Binder object: Must be static class or memory leak may occur - - /** - * This class implements the IClient interface - or actually it validates the preconditions for - * calling the actual functionality in the MapClientService, and calls it. - */ - @VisibleForTesting - static class Binder extends IBluetoothMapClient.Stub implements IProfileServiceBinder { - private MapClientService mService; - - Binder(MapClientService service) { - mService = service; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private MapClientService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - MapClientService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !(getCallingUserHandle().isSystem() - || Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG)) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - return service; - } - - @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) - private MapClientService getServiceAndEnforcePrivileged(AttributionSource source) { - // Cache mService because it can change while getService is called - MapClientService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !(getCallingUserHandle().isSystem() - || Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG)) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service; - } - - @Override - public boolean connect(BluetoothDevice device, AttributionSource source) { - Log.v(TAG, "connect()"); - - MapClientService service = getServiceAndEnforcePrivileged(source); - if (service == null) { - return false; - } - - return service.connect(device); - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - Log.v(TAG, "disconnect()"); - - MapClientService service = getServiceAndEnforcePrivileged(source); - if (service == null) { - return false; - } - - return service.disconnect(device); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - Log.v(TAG, "getConnectedDevices()"); - - MapClientService service = getServiceAndEnforcePrivileged(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - Log.v(TAG, "getDevicesMatchingConnectionStates()"); - - MapClientService service = getServiceAndEnforcePrivileged(source); - if (service == null) { - return Collections.emptyList(); - } - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - Log.v(TAG, "getConnectionState()"); - - MapClientService service = getServiceAndEnforcePrivileged(source); - if (service == null) { - return STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - Log.v(TAG, "setConnectionPolicy()"); - - MapClientService service = getServiceAndEnforcePrivileged(source); - if (service == null) { - return false; - } - - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - Log.v(TAG, "getConnectionPolicy()"); - - MapClientService service = getServiceAndEnforcePrivileged(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - return service.getConnectionPolicy(device); - } - - @Override - public boolean sendMessage( - BluetoothDevice device, - Uri[] contacts, - String message, - PendingIntent sentIntent, - PendingIntent deliveredIntent, - AttributionSource source) { - Log.v(TAG, "sendMessage()"); - - MapClientService service = getService(source); - if (service == null) { - return false; - } - - Log.d(TAG, "Checking Permission of sendMessage"); - mService.enforceCallingOrSelfPermission( - Manifest.permission.SEND_SMS, "Need SEND_SMS permission"); - - return service.sendMessage(device, contacts, message, sentIntent, deliveredIntent); - } - } - public void aclDisconnected(BluetoothDevice device, int transport) { mHandler.post(() -> handleAclDisconnected(device, transport)); } diff --git a/android/app/src/com/android/bluetooth/mapclient/MapClientServiceBinder.java b/android/app/src/com/android/bluetooth/mapclient/MapClientServiceBinder.java new file mode 100644 index 0000000000..d6be8975e8 --- /dev/null +++ b/android/app/src/com/android/bluetooth/mapclient/MapClientServiceBinder.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.mapclient; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import android.Manifest; +import android.annotation.RequiresPermission; +import android.app.PendingIntent; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IBluetoothMapClient; +import android.content.AttributionSource; +import android.net.Uri; +import android.util.Log; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +/** + * This class implements the IClient interface - or actually it validates the preconditions for + * calling the actual functionality in the MapClientService, and calls it. + */ +class MapClientServiceBinder extends IBluetoothMapClient.Stub implements IProfileServiceBinder { + private static final String TAG = MapClientServiceBinder.class.getSimpleName(); + + private MapClientService mService; + + MapClientServiceBinder(MapClientService service) { + mService = service; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private MapClientService getService(AttributionSource source) { + MapClientService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !(getCallingUserHandle().isSystem() + || Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG)) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + return service; + } + + @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) + private MapClientService getServiceAndEnforcePrivileged(AttributionSource source) { + MapClientService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !(getCallingUserHandle().isSystem() + || Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG)) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service; + } + + @Override + public boolean connect(BluetoothDevice device, AttributionSource source) { + Log.v(TAG, "connect()"); + + MapClientService service = getServiceAndEnforcePrivileged(source); + if (service == null) { + return false; + } + return service.connect(device); + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + Log.v(TAG, "disconnect()"); + + MapClientService service = getServiceAndEnforcePrivileged(source); + if (service == null) { + return false; + } + return service.disconnect(device); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + Log.v(TAG, "getConnectedDevices()"); + + MapClientService service = getServiceAndEnforcePrivileged(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + Log.v(TAG, "getDevicesMatchingConnectionStates()"); + + MapClientService service = getServiceAndEnforcePrivileged(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + Log.v(TAG, "getConnectionState()"); + + MapClientService service = getServiceAndEnforcePrivileged(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + Log.v(TAG, "setConnectionPolicy()"); + + MapClientService service = getServiceAndEnforcePrivileged(source); + if (service == null) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + Log.v(TAG, "getConnectionPolicy()"); + + MapClientService service = getServiceAndEnforcePrivileged(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + return service.getConnectionPolicy(device); + } + + @Override + public boolean sendMessage( + BluetoothDevice device, + Uri[] contacts, + String message, + PendingIntent sentIntent, + PendingIntent deliveredIntent, + AttributionSource source) { + Log.v(TAG, "sendMessage()"); + + MapClientService service = getService(source); + if (service == null) { + return false; + } + + Log.d(TAG, "Checking Permission of sendMessage"); + mService.enforceCallingOrSelfPermission( + Manifest.permission.SEND_SMS, "Need SEND_SMS permission"); + + return service.sendMessage(device, contacts, message, sentIntent, deliveredIntent); + } +} diff --git a/android/app/src/com/android/bluetooth/mapclient/OWNERS b/android/app/src/com/android/bluetooth/mapclient/OWNERS deleted file mode 100644 index b0b54fc3d2..0000000000 --- a/android/app/src/com/android/bluetooth/mapclient/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -include /OWNERS_automotive -include /OWNERS_content diff --git a/android/app/src/com/android/bluetooth/mcp/McpService.java b/android/app/src/com/android/bluetooth/mcp/McpService.java index c0ba4f12bb..6f08be0061 100644 --- a/android/app/src/com/android/bluetooth/mcp/McpService.java +++ b/android/app/src/com/android/bluetooth/mcp/McpService.java @@ -17,12 +17,9 @@ package com.android.bluetooth.mcp; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; import android.bluetooth.BluetoothDevice; -import android.bluetooth.IBluetoothMcpServiceManager; -import android.content.AttributionSource; import android.content.Context; import android.os.ParcelUuid; import android.sysprop.BluetoothProperties; @@ -88,7 +85,7 @@ public class McpService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new BluetoothMcpServiceBinder(this); + return new McpServiceBinder(this); } @Override @@ -198,41 +195,4 @@ public class McpService extends ProfileService { int ccid, BluetoothDevice device, ParcelUuid charUuid, boolean doNotify) { mGmcs.setNotificationSubscription(ccid, device, charUuid, doNotify); } - - /** Binder object: must be a static class or memory leak may occur */ - static class BluetoothMcpServiceBinder extends IBluetoothMcpServiceManager.Stub - implements IProfileServiceBinder { - private McpService mService; - - BluetoothMcpServiceBinder(McpService svc) { - mService = svc; - } - - private McpService getService() { - if (mService != null && mService.isAvailable()) { - return mService; - } - Log.e(TAG, "getService() - Service requested, but not available!"); - return null; - } - - @Override - public void setDeviceAuthorized( - BluetoothDevice device, boolean isAuthorized, AttributionSource source) { - McpService service = getService(); - if (service == null) { - return; - } - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.setDeviceAuthorized(device, isAuthorized); - } - - @Override - public void cleanup() { - if (mService != null) { - mService.cleanup(); - } - mService = null; - } - } } diff --git a/android/app/src/com/android/bluetooth/mcp/McpServiceBinder.java b/android/app/src/com/android/bluetooth/mcp/McpServiceBinder.java new file mode 100644 index 0000000000..b22e87cadf --- /dev/null +++ b/android/app/src/com/android/bluetooth/mcp/McpServiceBinder.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.mcp; + +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IBluetoothMcpServiceManager; +import android.content.AttributionSource; +import android.util.Log; + +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +class McpServiceBinder extends IBluetoothMcpServiceManager.Stub implements IProfileServiceBinder { + private static final String TAG = McpServiceBinder.class.getSimpleName(); + + private McpService mService; + + McpServiceBinder(McpService svc) { + mService = svc; + } + + private McpService getService() { + if (mService != null && mService.isAvailable()) { + return mService; + } + Log.e(TAG, "getService() - Service requested, but not available!"); + return null; + } + + @Override + public void setDeviceAuthorized( + BluetoothDevice device, boolean isAuthorized, AttributionSource source) { + McpService service = getService(); + if (service == null) { + return; + } + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setDeviceAuthorized(device, isAuthorized); + } + + @Override + public void cleanup() { + if (mService != null) { + mService.cleanup(); + } + mService = null; + } +} diff --git a/android/app/src/com/android/bluetooth/mcp/OWNERS b/android/app/src/com/android/bluetooth/mcp/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/app/src/com/android/bluetooth/mcp/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java index 81c59f8ad2..d87bd420fe 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java @@ -25,7 +25,6 @@ import android.util.Log; import com.android.bluetooth.BluetoothMethodProxy; import com.android.bluetooth.Utils; -import com.android.bluetooth.flags.Flags; import java.util.ArrayList; @@ -82,10 +81,7 @@ public class BluetoothOppHandoverReceiver extends BroadcastReceiver { if (device == null) { return; } - String brEdrAddress = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(device) - : device.getIdentityAddress(); + String brEdrAddress = Utils.getBrEdrAddress(device); Log.d(TAG, "Adding " + brEdrAddress + " to acceptlist"); BluetoothOppManager.getInstance(context).addToAcceptlist(brEdrAddress); } else if (action.equals(Constants.ACTION_STOP_HANDOVER)) { diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java index 048c134848..73cba4e954 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java @@ -248,6 +248,12 @@ public class BluetoothOppLauncherActivity extends Activity { permittedUris, false /* isHandover */, true /* fromExternal */); + if (Flags.sendOppDevicePickerExtraIntent()) { + BluetoothOppUtility + .grantPermissionToNearbyComponent( + BluetoothOppLauncherActivity.this, + uris); + } // Done getting file info..Launch device picker // and finish this activity launchDevicePicker(); @@ -322,6 +328,11 @@ public class BluetoothOppLauncherActivity extends Activity { in1.putExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE, getPackageName()); in1.putExtra( BluetoothDevicePicker.EXTRA_LAUNCH_CLASS, BluetoothOppReceiver.class.getName()); + if (Flags.sendOppDevicePickerExtraIntent()) { + in1.putExtra( + BluetoothDevicePicker.EXTRA_DEVICE_PICKER_ORIGINAL_SEND_INTENT, + getIntent()); + } Log.v(TAG, "Launching " + BluetoothDevicePicker.ACTION_LAUNCH); startActivity(in1); } @@ -555,6 +566,10 @@ public class BluetoothOppLauncherActivity extends Activity { void sendFileInfo(String mimeType, String uriString, boolean isHandover, boolean fromExternal) { BluetoothOppManager manager = BluetoothOppManager.getInstance(getApplicationContext()); try { + if (Flags.sendOppDevicePickerExtraIntent()) { + BluetoothOppUtility.grantPermissionToNearbyComponent( + this, List.of(Uri.parse(uriString))); + } manager.saveSendingFileInfo(mimeType, uriString, isHandover, fromExternal); launchDevicePicker(); finish(); diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppManager.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppManager.java index 730c1e9ce2..c745f243d4 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppManager.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppManager.java @@ -54,7 +54,6 @@ import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.R; import com.android.bluetooth.Utils; import com.android.bluetooth.content_profiles.ContentProfileErrorReportUtils; -import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; @@ -480,11 +479,7 @@ public class BluetoothOppManager { } values.put(BluetoothShare.MIMETYPE, contentType); - values.put( - BluetoothShare.DESTINATION, - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(mRemoteDevice) - : mRemoteDevice.getIdentityAddress()); + values.put(BluetoothShare.DESTINATION, Utils.getBrEdrAddress(mRemoteDevice)); values.put(BluetoothShare.TIMESTAMP, ts); if (mIsHandoverInitiated) { values.put( @@ -512,11 +507,7 @@ public class BluetoothOppManager { ContentValues values = new ContentValues(); values.put(BluetoothShare.URI, mUri); values.put(BluetoothShare.MIMETYPE, mTypeOfSingleFile); - values.put( - BluetoothShare.DESTINATION, - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(mRemoteDevice) - : mRemoteDevice.getIdentityAddress()); + values.put(BluetoothShare.DESTINATION, Utils.getBrEdrAddress(mRemoteDevice)); if (mIsHandoverInitiated) { values.put( BluetoothShare.USER_CONFIRMATION, diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppPreference.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppPreference.java index 6164cb4f58..114adfe631 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppPreference.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppPreference.java @@ -32,7 +32,6 @@ package com.android.bluetooth.opp; -import android.annotation.SuppressLint; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothUtils; import android.content.Context; @@ -41,7 +40,6 @@ import android.content.SharedPreferences.Editor; import android.util.Log; import com.android.bluetooth.Utils; -import com.android.bluetooth.flags.Flags; import java.util.HashMap; @@ -87,11 +85,11 @@ public class BluetoothOppPreference { } private static String getChannelKey(BluetoothDevice remoteDevice, int uuid) { - return getBrEdrAddress(remoteDevice) + "_" + Integer.toHexString(uuid); + return Utils.getBrEdrAddress(remoteDevice) + "_" + Integer.toHexString(uuid); } public String getName(BluetoothDevice remoteDevice) { - String identityAddress = getBrEdrAddress(remoteDevice); + String identityAddress = Utils.getBrEdrAddress(remoteDevice); if (identityAddress != null && identityAddress.equals("FF:FF:FF:00:00:00")) { return "localhost"; } @@ -113,7 +111,8 @@ public class BluetoothOppPreference { Log.v( TAG, "getChannel for " - + BluetoothUtils.toAnonymizedAddress(getBrEdrAddress(remoteDevice)) + + BluetoothUtils.toAnonymizedAddress( + Utils.getBrEdrAddress(remoteDevice)) + "_" + Integer.toHexString(uuid) + " as " @@ -123,7 +122,7 @@ public class BluetoothOppPreference { } public void setName(BluetoothDevice remoteDevice, String name) { - String brEdrAddress = getBrEdrAddress(remoteDevice); + String brEdrAddress = Utils.getBrEdrAddress(remoteDevice); Log.v( TAG, "setName for " + BluetoothUtils.toAnonymizedAddress(brEdrAddress) + " to " + name); @@ -139,7 +138,7 @@ public class BluetoothOppPreference { Log.v( TAG, "setChannel for " - + BluetoothUtils.toAnonymizedAddress(getBrEdrAddress(remoteDevice)) + + BluetoothUtils.toAnonymizedAddress(Utils.getBrEdrAddress(remoteDevice)) + "_" + Integer.toHexString(uuid) + " to " @@ -163,7 +162,7 @@ public class BluetoothOppPreference { public void removeName(BluetoothDevice remoteDevice) { Editor ed = mNamePreference.edit(); - String key = getBrEdrAddress(remoteDevice); + String key = Utils.getBrEdrAddress(remoteDevice); ed.remove(key); ed.apply(); mNames.remove(key); @@ -175,12 +174,4 @@ public class BluetoothOppPreference { Log.d(TAG, "Dumping Channels: "); Log.d(TAG, mChannels.toString()); } - - @SuppressLint("AndroidFrameworkRequiresPermission") - private static String getBrEdrAddress(BluetoothDevice device) { - if (Flags.identityAddressNullIfNotKnown()) { - return Utils.getBrEdrAddress(device); - } - return device.getIdentityAddress(); - } } diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java index eb9b7f91c4..77dadd9a65 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java @@ -52,7 +52,6 @@ import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.R; import com.android.bluetooth.Utils; import com.android.bluetooth.content_profiles.ContentProfileErrorReportUtils; -import com.android.bluetooth.flags.Flags; /** * Receives and handles: system broadcasts; Intents from other applications; Intents from @@ -81,9 +80,7 @@ public class BluetoothOppReceiver extends BroadcastReceiver { TAG, "Received BT device selected intent, bt device: " + BluetoothUtils.toAnonymizedAddress( - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(remoteDevice) - : remoteDevice.getIdentityAddress())); + Utils.getBrEdrAddress(remoteDevice))); // Insert transfer session record to database mOppManager.startTransfer(remoteDevice); diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java index 2548b9e45c..f043cbcc53 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java @@ -121,7 +121,7 @@ public class BluetoothOppService extends ProfileService implements IObexConnecti // Since ContentObserver is created with Handler, onChange() can be called // even after the observer is unregistered. - if (Flags.oppIgnoreContentObserverAfterServiceStop() && mObserver != this) { + if (mObserver != this) { Log.d(TAG, "onChange() called after stop() is called."); return; } @@ -1346,9 +1346,7 @@ public class BluetoothOppService extends ProfileService implements IObexConnecti + socket + " \n :device :" + BluetoothUtils.toAnonymizedAddress( - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(device, mAdapterService) - : mAdapterService.getIdentityAddress(device.getAddress()))); + Utils.getBrEdrAddress(device, mAdapterService))); if (!mAcceptNewConnections) { Log.d(TAG, " onConnect BluetoothSocket :" + socket + " rejected"); return false; diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppTransfer.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppTransfer.java index 1ff73d1b48..5e92f1e81e 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppTransfer.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppTransfer.java @@ -63,7 +63,6 @@ import com.android.bluetooth.BluetoothObexTransport; import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.Utils; import com.android.bluetooth.content_profiles.ContentProfileErrorReportUtils; -import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.VisibleForTesting; import com.android.obex.ObexTransport; @@ -116,7 +115,8 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch Log.e( TAG, "device : " - + BluetoothUtils.toAnonymizedAddress(getBrEdrAddress(device)) + + BluetoothUtils.toAnonymizedAddress( + Utils.getBrEdrAddress(device)) + " mBatch :" + mBatch + " mCurrentShare :" @@ -133,7 +133,8 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch Log.v( TAG, "Device :" - + BluetoothUtils.toAnonymizedAddress(getBrEdrAddress(device)) + + BluetoothUtils.toAnonymizedAddress( + Utils.getBrEdrAddress(device)) + "- OPP device: " + mBatch.mDestination + " \n mCurrentShare.mConfirm == " @@ -180,8 +181,8 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch 3); return; } - String deviceIdentityAddress = getBrEdrAddress(device); - String transferDeviceIdentityAddress = getBrEdrAddress(mDevice); + String deviceIdentityAddress = Utils.getBrEdrAddress(device); + String transferDeviceIdentityAddress = Utils.getBrEdrAddress(mDevice); if (deviceIdentityAddress == null || transferDeviceIdentityAddress == null || !deviceIdentityAddress.equalsIgnoreCase( @@ -1008,11 +1009,4 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch } } } - - private static String getBrEdrAddress(BluetoothDevice device) { - if (Flags.identityAddressNullIfNotKnown()) { - return Utils.getBrEdrAddress(device); - } - return device.getIdentityAddress(); - } } diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppUtility.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppUtility.java index d7b75bfde2..4e8892ab35 100644 --- a/android/app/src/com/android/bluetooth/opp/BluetoothOppUtility.java +++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppUtility.java @@ -38,6 +38,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProtoEnums; import android.content.ActivityNotFoundException; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; @@ -50,6 +51,7 @@ import android.net.Uri; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.SystemProperties; +import android.provider.Settings; import android.util.EventLog; import android.util.Log; @@ -77,6 +79,9 @@ import java.util.concurrent.ConcurrentHashMap; public class BluetoothOppUtility { private static final String TAG = BluetoothOppUtility.class.getSimpleName(); + // TODO(b/398120192): use API instead of a hardcode string. + private static final String NEARBY_SHARING_COMPONENT = "nearby_sharing_component"; + /** Whether the device has the "nosdcard" characteristic, or null if not-yet-known. */ private static Boolean sNoSdCard = null; @@ -572,4 +577,30 @@ public class BluetoothOppUtility { NotificationManager nm = ctx.getSystemService(NotificationManager.class); nm.cancel(BluetoothOppNotification.NOTIFICATION_ID_PROGRESS); } + + /** Grants uri read permission to nearby sharing component. */ + static void grantPermissionToNearbyComponent(Context context, List<Uri> uris) { + String packageName = getNearbyComponentPackageName(context); + if (packageName == null) { + return; + } + for (Uri uri : uris) { + BluetoothMethodProxy.getInstance() + .grantUriPermission( + context, packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + } + + private static String getNearbyComponentPackageName(Context context) { + String componentString = + Settings.Secure.getString(context.getContentResolver(), NEARBY_SHARING_COMPONENT); + if (componentString == null) { + return null; + } + ComponentName componentName = ComponentName.unflattenFromString(componentString); + if (componentName == null) { + return null; + } + return componentName.getPackageName(); + } } diff --git a/android/app/src/com/android/bluetooth/opp/OWNERS b/android/app/src/com/android/bluetooth/opp/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/src/com/android/bluetooth/opp/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/src/com/android/bluetooth/pan/OWNERS b/android/app/src/com/android/bluetooth/pan/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/src/com/android/bluetooth/pan/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/src/com/android/bluetooth/pan/PanService.java b/android/app/src/com/android/bluetooth/pan/PanService.java index 311e100b52..9196288928 100644 --- a/android/app/src/com/android/bluetooth/pan/PanService.java +++ b/android/app/src/com/android/bluetooth/pan/PanService.java @@ -17,8 +17,6 @@ package com.android.bluetooth.pan; import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; -import static android.Manifest.permission.TETHER_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; @@ -30,15 +28,12 @@ import static android.bluetooth.BluetoothUtils.logRemoteException; import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNullElseGet; -import android.annotation.RequiresPermission; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothPan.LocalPanRole; import android.bluetooth.BluetoothPan.RemotePanRole; import android.bluetooth.BluetoothProfile; -import android.bluetooth.IBluetoothPan; import android.bluetooth.IBluetoothPanCallback; -import android.content.AttributionSource; import android.content.Intent; import android.content.res.Resources.NotFoundException; import android.net.TetheringInterface; @@ -55,12 +50,10 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.storage.DatabaseManager; -import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.HandlerExecutor; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -105,9 +98,7 @@ public class PanService extends ProfileService { Log.e(TAG, "Error setting up tether interface: " + error); for (BluetoothDevice device : mPanDevices.keySet()) { mNativeInterface.disconnect( - Flags.panUseIdentityAddress() - ? Utils.getByteBrEdrAddress(mAdapterService, device) - : Utils.getByteAddress(device)); + Utils.getByteBrEdrAddress(mAdapterService, device)); } mPanDevices.clear(); mIsTethering = false; @@ -154,7 +145,7 @@ public class PanService extends ProfileService { @Override public IProfileServiceBinder initBinder() { - return new BluetoothPanBinder(this); + return new PanServiceBinder(this); } public static synchronized PanService getPanService() { @@ -218,9 +209,7 @@ public class PanService extends ProfileService { case MESSAGE_CONNECT: BluetoothDevice connectDevice = (BluetoothDevice) msg.obj; if (!mNativeInterface.connect( - Flags.identityAddressNullIfNotKnown() - ? Utils.getByteBrEdrAddress(mAdapterService, connectDevice) - : mAdapterService.getByteIdentityAddress(connectDevice))) { + Utils.getByteBrEdrAddress(mAdapterService, connectDevice))) { handlePanDeviceStateChange( connectDevice, null, @@ -238,9 +227,7 @@ public class PanService extends ProfileService { case MESSAGE_DISCONNECT: BluetoothDevice disconnectDevice = (BluetoothDevice) msg.obj; if (!mNativeInterface.disconnect( - Flags.identityAddressNullIfNotKnown() - ? Utils.getByteBrEdrAddress(mAdapterService, disconnectDevice) - : mAdapterService.getByteIdentityAddress(disconnectDevice))) { + Utils.getByteBrEdrAddress(mAdapterService, disconnectDevice))) { handlePanDeviceStateChange( disconnectDevice, mPanIfName, @@ -276,137 +263,6 @@ public class PanService extends ProfileService { } } - /** Handlers for incoming service calls */ - @VisibleForTesting - static class BluetoothPanBinder extends IBluetoothPan.Stub implements IProfileServiceBinder { - private PanService mService; - - BluetoothPanBinder(PanService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private PanService getService(AttributionSource source) { - if (Utils.isInstrumentationTestMode()) { - return mService; - } - if (!Utils.checkServiceAvailable(mService, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(mService, TAG) - || !Utils.checkConnectPermissionForDataDelivery(mService, source, TAG)) { - return null; - } - return mService; - } - - @Override - public boolean connect(BluetoothDevice device, AttributionSource source) { - PanService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.connect(device); - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - PanService service = getService(source); - if (service == null) { - return false; - } - - return service.disconnect(device); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - PanService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - PanService service = getService(source); - if (service == null) { - return BluetoothPan.STATE_DISCONNECTED; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectionState(device); - } - - @Override - public boolean isTetheringOn(AttributionSource source) { - // TODO(BT) have a variable marking the on/off state - PanService service = getService(source); - if (service == null) { - return false; - } - - return service.isTetheringOn(); - } - - @Override - public void setBluetoothTethering( - IBluetoothPanCallback callback, int id, boolean value, AttributionSource source) { - PanService service = getService(source); - if (service == null) { - return; - } - - Log.d( - TAG, - "setBluetoothTethering:" - + (" value=" + value) - + (" pkgName= " + source.getPackageName()) - + (" mTetherOn= " + service.mTetherOn)); - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.enforceCallingOrSelfPermission(TETHER_PRIVILEGED, null); - - service.setBluetoothTethering(callback, id, source.getUid(), value); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - PanService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - PanService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getDevicesMatchingConnectionStates(states); - } - } - public boolean connect(BluetoothDevice device) { if (mUserManager.isGuestUser()) { Log.w(TAG, "Guest user does not have the permission to change the WiFi network"); @@ -641,10 +497,7 @@ public class PanService extends ProfileService { "handlePanDeviceStateChange BT tethering is off/Local role" + " is PANU drop the connection"); mPanDevices.remove(device); - mNativeInterface.disconnect( - Flags.panUseIdentityAddress() - ? Utils.getByteBrEdrAddress(mAdapterService, device) - : Utils.getByteAddress(device)); + mNativeInterface.disconnect(Utils.getByteBrEdrAddress(mAdapterService, device)); return; } Log.d(TAG, "handlePanDeviceStateChange LOCAL_NAP_ROLE:REMOTE_PANU_ROLE"); diff --git a/android/app/src/com/android/bluetooth/pan/PanServiceBinder.java b/android/app/src/com/android/bluetooth/pan/PanServiceBinder.java new file mode 100644 index 0000000000..e3baae21dc --- /dev/null +++ b/android/app/src/com/android/bluetooth/pan/PanServiceBinder.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.pan; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.Manifest.permission.TETHER_PRIVILEGED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothPan; +import android.bluetooth.IBluetoothPan; +import android.bluetooth.IBluetoothPanCallback; +import android.content.AttributionSource; +import android.util.Log; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +/** Handlers for incoming service calls */ +class PanServiceBinder extends IBluetoothPan.Stub implements IProfileServiceBinder { + private static final String TAG = PanServiceBinder.class.getSimpleName(); + + private PanService mService; + + PanServiceBinder(PanService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private PanService getService(AttributionSource source) { + if (Utils.isInstrumentationTestMode()) { + return mService; + } + if (!Utils.checkServiceAvailable(mService, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(mService, TAG) + || !Utils.checkConnectPermissionForDataDelivery(mService, source, TAG)) { + return null; + } + return mService; + } + + @Override + public boolean connect(BluetoothDevice device, AttributionSource source) { + PanService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.connect(device); + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + PanService service = getService(source); + if (service == null) { + return false; + } + return service.disconnect(device); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + PanService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + PanService service = getService(source); + if (service == null) { + return BluetoothPan.STATE_DISCONNECTED; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionState(device); + } + + @Override + public boolean isTetheringOn(AttributionSource source) { + // TODO(BT) have a variable marking the on/off state + PanService service = getService(source); + if (service == null) { + return false; + } + return service.isTetheringOn(); + } + + @Override + public void setBluetoothTethering( + IBluetoothPanCallback callback, int id, boolean value, AttributionSource source) { + PanService service = getService(source); + if (service == null) { + return; + } + + Log.d( + TAG, + "setBluetoothTethering:" + + (" value=" + value) + + (" pkgName= " + source.getPackageName()) + + (" mTetherOn= " + service.isTetheringOn())); + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.enforceCallingOrSelfPermission(TETHER_PRIVILEGED, null); + + service.setBluetoothTethering(callback, id, source.getUid(), value); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + PanService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + PanService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getDevicesMatchingConnectionStates(states); + } +} diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapActivity.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapActivity.java index 7223516e88..18fff92890 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapActivity.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapActivity.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapAuthenticator.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapAuthenticator.java index 55419908eb..2e788d424a 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapAuthenticator.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapAuthenticator.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapConfig.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapConfig.java index 6fec2895e6..391d759065 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapConfig.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapConfig.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java index 88f7023b03..c5bb01f426 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java index 00194f5d78..2d67fc9947 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -17,7 +17,6 @@ package com.android.bluetooth.pbap; import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothDevice.ACCESS_ALLOWED; import static android.bluetooth.BluetoothDevice.ACCESS_REJECTED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; @@ -28,19 +27,15 @@ import static com.android.bluetooth.Utils.joinUninterruptibly; import static java.util.Objects.requireNonNull; -import android.annotation.RequiresPermission; import android.app.Activity; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; -import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProtoEnums; import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothUtils; -import android.bluetooth.IBluetoothPbap; -import android.content.AttributionSource; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -75,7 +70,6 @@ import com.android.bluetooth.util.DevicePolicyUtils; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -734,7 +728,7 @@ public class BluetoothPbapService extends ProfileService implements IObexConnect @Override protected IProfileServiceBinder initBinder() { - return new PbapBinder(this); + return new BluetoothPbapServiceBinder(this); } @Override @@ -775,97 +769,6 @@ public class BluetoothPbapService extends ProfileService implements IObexConnect sBluetoothPbapService = instance; } - @VisibleForTesting - static class PbapBinder extends IBluetoothPbap.Stub implements IProfileServiceBinder { - private BluetoothPbapService mService; - - PbapBinder(BluetoothPbapService service) { - Log.v(TAG, "PbapBinder()"); - mService = service; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private BluetoothPbapService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - BluetoothPbapService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - return service; - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - Log.d(TAG, "getConnectedDevices"); - BluetoothPbapService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - Log.d(TAG, "getDevicesMatchingConnectionStates"); - BluetoothPbapService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - Log.d(TAG, "getConnectionState: " + device); - BluetoothPbapService service = getService(source); - if (service == null) { - return BluetoothAdapter.STATE_DISCONNECTED; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectionState(device); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - Log.d(TAG, "setConnectionPolicy for device=" + device + " policy=" + connectionPolicy); - BluetoothPbapService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public void disconnect(BluetoothDevice device, AttributionSource source) { - Log.d(TAG, "disconnect"); - BluetoothPbapService service = getService(source); - if (service == null) { - return; - } - service.disconnect(device); - } - } - @Override public boolean onConnect(BluetoothDevice remoteDevice, BluetoothSocket socket) { if (remoteDevice == null || socket == null) { diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapServiceBinder.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapServiceBinder.java new file mode 100644 index 0000000000..67ad07169a --- /dev/null +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapServiceBinder.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.pbap; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IBluetoothPbap; +import android.content.AttributionSource; +import android.util.Log; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +class BluetoothPbapServiceBinder extends IBluetoothPbap.Stub implements IProfileServiceBinder { + private static final String TAG = BluetoothPbapServiceBinder.class.getSimpleName(); + + private BluetoothPbapService mService; + + BluetoothPbapServiceBinder(BluetoothPbapService service) { + mService = service; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private BluetoothPbapService getService(AttributionSource source) { + BluetoothPbapService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + return service; + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + Log.d(TAG, "getConnectedDevices"); + BluetoothPbapService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + Log.d(TAG, "getDevicesMatchingConnectionStates"); + BluetoothPbapService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + Log.d(TAG, "getConnectionState: " + device); + BluetoothPbapService service = getService(source); + if (service == null) { + return BluetoothAdapter.STATE_DISCONNECTED; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionState(device); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + Log.d(TAG, "setConnectionPolicy for device=" + device + " policy=" + connectionPolicy); + BluetoothPbapService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public void disconnect(BluetoothDevice device, AttributionSource source) { + Log.d(TAG, "disconnect"); + BluetoothPbapService service = getService(source); + if (service == null) { + return; + } + service.disconnect(device); + } +} diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java index db427991a2..c63ec28105 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManager.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapUtils.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapUtils.java index e70706f84d..75a1b3d9f8 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapUtils.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapUtils.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java index 5fa66a785c..c3b08a2e89 100644 --- a/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java +++ b/android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/android/app/src/com/android/bluetooth/pbap/OWNERS b/android/app/src/com/android/bluetooth/pbap/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/src/com/android/bluetooth/pbap/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/src/com/android/bluetooth/pbapclient/OWNERS b/android/app/src/com/android/bluetooth/pbapclient/OWNERS deleted file mode 100644 index b0b54fc3d2..0000000000 --- a/android/app/src/com/android/bluetooth/pbapclient/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -include /OWNERS_automotive -include /OWNERS_content diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java index c83e856a72..9b75de98f0 100644 --- a/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java +++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java @@ -173,7 +173,7 @@ public class PbapClientService extends ProfileService { @Override public IProfileServiceBinder initBinder() { - return new PbapClientBinder(this); + return new PbapClientServiceBinder(this); } @Override diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientBinder.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientServiceBinder.java index f3bcd1e7b5..5a45896f02 100644 --- a/android/app/src/com/android/bluetooth/pbapclient/PbapClientBinder.java +++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientServiceBinder.java @@ -35,12 +35,12 @@ import java.util.Collections; import java.util.List; /** Handler for incoming service calls destined for PBAP Client */ -class PbapClientBinder extends IBluetoothPbapClient.Stub implements IProfileServiceBinder { - private static final String TAG = PbapClientBinder.class.getSimpleName(); +class PbapClientServiceBinder extends IBluetoothPbapClient.Stub implements IProfileServiceBinder { + private static final String TAG = PbapClientServiceBinder.class.getSimpleName(); private PbapClientService mService; - PbapClientBinder(PbapClientService service) { + PbapClientServiceBinder(PbapClientService service) { mService = service; } diff --git a/android/app/src/com/android/bluetooth/sap/OWNERS b/android/app/src/com/android/bluetooth/sap/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/src/com/android/bluetooth/sap/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/src/com/android/bluetooth/sap/SapService.java b/android/app/src/com/android/bluetooth/sap/SapService.java index c8bda8e046..54391d24e3 100644 --- a/android/app/src/com/android/bluetooth/sap/SapService.java +++ b/android/app/src/com/android/bluetooth/sap/SapService.java @@ -20,7 +20,6 @@ import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; -import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; @@ -37,8 +36,6 @@ import android.bluetooth.BluetoothSap; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothUuid; -import android.bluetooth.IBluetoothSap; -import android.content.AttributionSource; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -61,7 +58,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public class SapService extends ProfileService implements AdapterService.BluetoothStateCallback { @@ -672,7 +668,7 @@ public class SapService extends ProfileService implements AdapterService.Bluetoo @Override protected IProfileServiceBinder initBinder() { - return new SapBinder(this); + return new SapServiceBinder(this); } @Override @@ -881,145 +877,4 @@ public class SapService extends ProfileService implements AdapterService.Bluetoo mSessionStatusHandler.sendEmptyMessage(MSG_SERVERSESSION_CLOSE); } } - - // Binder object: Must be static class or memory leak may occur - - /** - * This class implements the IBluetoothSap interface - or actually it validates the - * preconditions for calling the actual functionality in the SapService, and calls it. - */ - private static class SapBinder extends IBluetoothSap.Stub implements IProfileServiceBinder { - private SapService mService; - - SapBinder(SapService service) { - Log.v(TAG, "SapBinder()"); - mService = service; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private SapService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - SapService service = mService; - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - return service; - } - - @Override - public int getState(AttributionSource source) { - Log.v(TAG, "getState()"); - - SapService service = getService(source); - if (service == null) { - return BluetoothSap.STATE_DISCONNECTED; - } - - return service.getState(); - } - - @Override - public BluetoothDevice getClient(AttributionSource source) { - Log.v(TAG, "getClient()"); - - SapService service = getService(source); - if (service == null) { - return null; - } - - Log.v(TAG, "getClient() - returning " + service.getRemoteDevice()); - return service.getRemoteDevice(); - } - - @Override - public boolean isConnected(BluetoothDevice device, AttributionSource source) { - Log.v(TAG, "isConnected()"); - - SapService service = getService(source); - if (service == null) { - return false; - } - - return service.getConnectionState(device) == STATE_CONNECTED; - } - - @Override - public boolean disconnect(BluetoothDevice device, AttributionSource source) { - Log.v(TAG, "disconnect()"); - - SapService service = getService(source); - if (service == null) { - return false; - } - - return service.disconnect(device); - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - Log.v(TAG, "getConnectedDevices()"); - - SapService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - Log.v(TAG, "getDevicesMatchingConnectionStates()"); - - SapService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - Log.v(TAG, "getConnectionState()"); - - SapService service = getService(source); - if (service == null) { - return STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - SapService service = getService(source); - if (service == null) { - return false; - } - - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - SapService service = getService(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - return service.getConnectionPolicy(device); - } - } } diff --git a/android/app/src/com/android/bluetooth/sap/SapServiceBinder.java b/android/app/src/com/android/bluetooth/sap/SapServiceBinder.java new file mode 100644 index 0000000000..4c8a96901a --- /dev/null +++ b/android/app/src/com/android/bluetooth/sap/SapServiceBinder.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.sap; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSap; +import android.bluetooth.IBluetoothSap; +import android.content.AttributionSource; +import android.util.Log; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.Collections; +import java.util.List; + +/** + * This class implements the IBluetoothSap interface - or actually it validates the preconditions + * for calling the actual functionality in the SapService, and calls it. + */ +class SapServiceBinder extends IBluetoothSap.Stub implements IProfileServiceBinder { + private static final String TAG = SapServiceBinder.class.getSimpleName(); + + private SapService mService; + + SapServiceBinder(SapService service) { + mService = service; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private SapService getService(AttributionSource source) { + SapService service = mService; + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + return service; + } + + @Override + public int getState(AttributionSource source) { + Log.v(TAG, "getState()"); + + SapService service = getService(source); + if (service == null) { + return BluetoothSap.STATE_DISCONNECTED; + } + return service.getState(); + } + + @Override + public BluetoothDevice getClient(AttributionSource source) { + Log.v(TAG, "getClient()"); + + SapService service = getService(source); + if (service == null) { + return null; + } + + Log.v(TAG, "getClient() - returning " + service.getRemoteDevice()); + return service.getRemoteDevice(); + } + + @Override + public boolean isConnected(BluetoothDevice device, AttributionSource source) { + Log.v(TAG, "isConnected()"); + + SapService service = getService(source); + if (service == null) { + return false; + } + return service.getConnectionState(device) == STATE_CONNECTED; + } + + @Override + public boolean disconnect(BluetoothDevice device, AttributionSource source) { + Log.v(TAG, "disconnect()"); + + SapService service = getService(source); + if (service == null) { + return false; + } + return service.disconnect(device); + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + Log.v(TAG, "getConnectedDevices()"); + + SapService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + Log.v(TAG, "getDevicesMatchingConnectionStates()"); + + SapService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + Log.v(TAG, "getConnectionState()"); + + SapService service = getService(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + SapService service = getService(source); + if (service == null) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + SapService service = getService(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + return service.getConnectionPolicy(device); + } +} diff --git a/android/app/src/com/android/bluetooth/sdp/SdpManager.java b/android/app/src/com/android/bluetooth/sdp/SdpManager.java index 3a316f8457..de6193aeb2 100644 --- a/android/app/src/com/android/bluetooth/sdp/SdpManager.java +++ b/android/app/src/com/android/bluetooth/sdp/SdpManager.java @@ -35,7 +35,6 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AbstractionLayer; import com.android.bluetooth.btservice.AdapterService; -import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; @@ -143,16 +142,10 @@ public class SdpManager { SdpSearchInstance getSearchInstance(byte[] address, byte[] uuidBytes) { String addressString = Utils.getAddressStringFromByte(address); - addressString = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(addressString, mAdapterService) - : mAdapterService.getIdentityAddress(addressString); + addressString = Utils.getBrEdrAddress(addressString, mAdapterService); ParcelUuid uuid = Utils.byteArrayToUuid(uuidBytes)[0]; for (SdpSearchInstance inst : mList) { - String instAddressString = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(inst.getDevice(), mAdapterService) - : mAdapterService.getIdentityAddress(inst.getDevice().getAddress()); + String instAddressString = Utils.getBrEdrAddress(inst.getDevice(), mAdapterService); if (instAddressString.equals(addressString) && inst.getUuid().equals(uuid)) { return inst; } @@ -161,15 +154,9 @@ public class SdpManager { } boolean isSearching(BluetoothDevice device, ParcelUuid uuid) { - String addressString = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(device, mAdapterService) - : mAdapterService.getIdentityAddress(device.getAddress()); + String addressString = Utils.getBrEdrAddress(device, mAdapterService); for (SdpSearchInstance inst : mList) { - String instAddressString = - Flags.identityAddressNullIfNotKnown() - ? Utils.getBrEdrAddress(inst.getDevice(), mAdapterService) - : mAdapterService.getIdentityAddress(inst.getDevice().getAddress()); + String instAddressString = Utils.getBrEdrAddress(inst.getDevice(), mAdapterService); if (instAddressString != null && addressString != null && instAddressString.equals(addressString) @@ -473,9 +460,7 @@ public class SdpManager { inst.startSearch(); // Trigger timeout message mNativeInterface.sdpSearch( - Flags.identityAddressNullIfNotKnown() - ? Utils.getByteBrEdrAddress(inst.getDevice()) - : mAdapterService.getByteIdentityAddress(inst.getDevice()), + Utils.getByteBrEdrAddress(inst.getDevice()), Utils.uuidToByteArray(inst.getUuid())); } else { // Else queue is empty. Log.d( diff --git a/android/app/src/com/android/bluetooth/tbs/TbsService.java b/android/app/src/com/android/bluetooth/tbs/TbsService.java index ebd25f8229..3bb2fa45e7 100644 --- a/android/app/src/com/android/bluetooth/tbs/TbsService.java +++ b/android/app/src/com/android/bluetooth/tbs/TbsService.java @@ -17,19 +17,13 @@ package com.android.bluetooth.tbs; -import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; import static java.util.Objects.requireNonNull; -import android.annotation.RequiresPermission; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeCall; -import android.bluetooth.IBluetoothLeCallControl; import android.bluetooth.IBluetoothLeCallControlCallback; -import android.content.AttributionSource; -import android.os.ParcelUuid; import android.os.RemoteException; import android.sysprop.BluetoothProperties; import android.util.Log; @@ -38,7 +32,6 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.le_audio.LeAudioService; -import com.android.internal.annotations.VisibleForTesting; import java.util.HashMap; import java.util.List; @@ -68,7 +61,7 @@ public class TbsService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new TbsServerBinder(this); + return new TbsServiceBinder(this); } @Override @@ -206,105 +199,6 @@ public class TbsService extends ProfileService { mTbsGeneric.clearInbandRingtoneSupport(device); } - /** Binder object: must be a static class or memory leak may occur */ - @VisibleForTesting - static class TbsServerBinder extends IBluetoothLeCallControl.Stub - implements IProfileServiceBinder { - private TbsService mService; - - TbsServerBinder(TbsService service) { - mService = service; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) - private TbsService getService(AttributionSource source) { - // Cache mService because it can change while getService is called - TbsService service = mService; - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service; - } - - @Override - public void registerBearer( - String token, - IBluetoothLeCallControlCallback callback, - String uci, - List<String> uriSchemes, - int capabilities, - String providerName, - int technology, - AttributionSource source) { - TbsService service = getService(source); - if (service != null) { - service.registerBearer( - token, callback, uci, uriSchemes, capabilities, providerName, technology); - } - } - - @Override - public void unregisterBearer(String token, AttributionSource source) { - TbsService service = getService(source); - if (service != null) { - service.unregisterBearer(token); - } - } - - @Override - public void requestResult(int ccid, int requestId, int result, AttributionSource source) { - TbsService service = getService(source); - if (service != null) { - service.requestResult(ccid, requestId, result); - } - } - - @Override - public void callAdded(int ccid, BluetoothLeCall call, AttributionSource source) { - TbsService service = getService(source); - if (service != null) { - service.callAdded(ccid, call); - } - } - - @Override - public void callRemoved(int ccid, ParcelUuid callId, int reason, AttributionSource source) { - TbsService service = getService(source); - if (service != null) { - service.callRemoved(ccid, callId.getUuid(), reason); - } - } - - @Override - public void callStateChanged( - int ccid, ParcelUuid callId, int state, AttributionSource source) { - TbsService service = getService(source); - if (service != null) { - service.callStateChanged(ccid, callId.getUuid(), state); - } - } - - @Override - public void currentCallsList( - int ccid, List<BluetoothLeCall> calls, AttributionSource source) { - TbsService service = getService(source); - if (service != null) { - service.currentCallsList(ccid, calls); - } - } - } - - @VisibleForTesting void registerBearer( String token, IBluetoothLeCallControlCallback callback, @@ -335,42 +229,36 @@ public class TbsService extends ProfileService { Log.d(TAG, "registerBearer: token=" + token + " success=" + success); } - @VisibleForTesting void unregisterBearer(String token) { Log.d(TAG, "unregisterBearer: token=" + token); mTbsGeneric.removeBearer(token); } - @VisibleForTesting public void requestResult(int ccid, int requestId, int result) { Log.d(TAG, "requestResult: ccid=" + ccid + " requestId=" + requestId + " result=" + result); mTbsGeneric.requestResult(ccid, requestId, result); } - @VisibleForTesting void callAdded(int ccid, BluetoothLeCall call) { Log.d(TAG, "callAdded: ccid=" + ccid + " call=" + call); mTbsGeneric.callAdded(ccid, call); } - @VisibleForTesting void callRemoved(int ccid, UUID callId, int reason) { Log.d(TAG, "callRemoved: ccid=" + ccid + " callId=" + callId + " reason=" + reason); mTbsGeneric.callRemoved(ccid, callId, reason); } - @VisibleForTesting void callStateChanged(int ccid, UUID callId, int state) { Log.d(TAG, "callStateChanged: ccid=" + ccid + " callId=" + callId + " state=" + state); mTbsGeneric.callStateChanged(ccid, callId, state); } - @VisibleForTesting void currentCallsList(int ccid, List<BluetoothLeCall> calls) { Log.d(TAG, "currentCallsList: ccid=" + ccid + " calls=" + calls); diff --git a/android/app/src/com/android/bluetooth/tbs/TbsServiceBinder.java b/android/app/src/com/android/bluetooth/tbs/TbsServiceBinder.java new file mode 100644 index 0000000000..88a1a3435c --- /dev/null +++ b/android/app/src/com/android/bluetooth/tbs/TbsServiceBinder.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.tbs; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; + +import android.annotation.RequiresPermission; +import android.bluetooth.BluetoothLeCall; +import android.bluetooth.IBluetoothLeCallControl; +import android.bluetooth.IBluetoothLeCallControlCallback; +import android.content.AttributionSource; +import android.os.ParcelUuid; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; + +import java.util.List; + +class TbsServiceBinder extends IBluetoothLeCallControl.Stub implements IProfileServiceBinder { + private static final String TAG = TbsServiceBinder.class.getSimpleName(); + + private TbsService mService; + + TbsServiceBinder(TbsService service) { + mService = service; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) + private TbsService getService(AttributionSource source) { + TbsService service = mService; + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service; + } + + @Override + public void registerBearer( + String token, + IBluetoothLeCallControlCallback callback, + String uci, + List<String> uriSchemes, + int capabilities, + String providerName, + int technology, + AttributionSource source) { + TbsService service = getService(source); + if (service != null) { + service.registerBearer( + token, callback, uci, uriSchemes, capabilities, providerName, technology); + } + } + + @Override + public void unregisterBearer(String token, AttributionSource source) { + TbsService service = getService(source); + if (service != null) { + service.unregisterBearer(token); + } + } + + @Override + public void requestResult(int ccid, int requestId, int result, AttributionSource source) { + TbsService service = getService(source); + if (service != null) { + service.requestResult(ccid, requestId, result); + } + } + + @Override + public void callAdded(int ccid, BluetoothLeCall call, AttributionSource source) { + TbsService service = getService(source); + if (service != null) { + service.callAdded(ccid, call); + } + } + + @Override + public void callRemoved(int ccid, ParcelUuid callId, int reason, AttributionSource source) { + TbsService service = getService(source); + if (service != null) { + service.callRemoved(ccid, callId.getUuid(), reason); + } + } + + @Override + public void callStateChanged(int ccid, ParcelUuid callId, int state, AttributionSource source) { + TbsService service = getService(source); + if (service != null) { + service.callStateChanged(ccid, callId.getUuid(), state); + } + } + + @Override + public void currentCallsList(int ccid, List<BluetoothLeCall> calls, AttributionSource source) { + TbsService service = getService(source); + if (service != null) { + service.currentCallsList(ccid, calls); + } + } +} diff --git a/android/app/src/com/android/bluetooth/vc/OWNERS b/android/app/src/com/android/bluetooth/vc/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/app/src/com/android/bluetooth/vc/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/app/src/com/android/bluetooth/vc/VolumeControlService.java b/android/app/src/com/android/bluetooth/vc/VolumeControlService.java index 628a36b6e8..b21d4e19b3 100644 --- a/android/app/src/com/android/bluetooth/vc/VolumeControlService.java +++ b/android/app/src/com/android/bluetooth/vc/VolumeControlService.java @@ -17,8 +17,6 @@ package com.android.bluetooth.vc; -import static android.Manifest.permission.BLUETOOTH_CONNECT; -import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothDevice.BOND_BONDED; import static android.bluetooth.BluetoothDevice.BOND_NONE; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; @@ -36,19 +34,14 @@ import static com.android.bluetooth.flags.Flags.vcpDeviceVolumeApiImprovements; import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNullElseGet; -import android.annotation.RequiresPermission; import android.bluetooth.AudioInputControl.AudioInputStatus; import android.bluetooth.AudioInputControl.AudioInputType; import android.bluetooth.AudioInputControl.GainMode; import android.bluetooth.AudioInputControl.Mute; -import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; -import android.bluetooth.IAudioInputCallback; -import android.bluetooth.IBluetoothVolumeControl; import android.bluetooth.IBluetoothVolumeControlCallback; -import android.content.AttributionSource; import android.media.AudioManager; import android.os.Handler; import android.os.HandlerThread; @@ -70,22 +63,13 @@ import com.android.bluetooth.le_audio.LeAudioService; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import libcore.util.SneakyThrow; - import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.Function; public class VolumeControlService extends ProfileService { private static final String TAG = VolumeControlService.class.getSimpleName(); @@ -166,7 +150,7 @@ public class VolumeControlService extends ProfileService { @Override protected IProfileServiceBinder initBinder() { - return new BluetoothVolumeControlBinder(this); + return new VolumeControlServiceBinder(this); } @Override @@ -209,6 +193,14 @@ public class VolumeControlService extends ProfileService { } } + Handler getHandler() { + return mHandler; + } + + Map<BluetoothDevice, VolumeControlInputDescriptor> getAudioInputs() { + return mAudioInputs; + } + /** * Get the VolumeControlService instance * @@ -534,7 +526,6 @@ public class VolumeControlService extends ProfileService { mNativeInterface.setExtAudioOutVolumeOffset(device, instanceId, volumeOffset); } - @VisibleForTesting synchronized void setDeviceVolume(BluetoothDevice device, int volume, boolean isGroupOp) { Log.d( TAG, @@ -1685,501 +1676,6 @@ public class VolumeControlService extends ProfileService { BluetoothProfile.VOLUME_CONTROL, device, fromState, toState); } - /** Binder object: must be a static class or memory leak may occur */ - @VisibleForTesting - static class BluetoothVolumeControlBinder extends IBluetoothVolumeControl.Stub - implements IProfileServiceBinder { - @VisibleForTesting boolean mIsTesting = false; - private VolumeControlService mService; - - BluetoothVolumeControlBinder(VolumeControlService svc) { - mService = svc; - } - - @Override - public void cleanup() { - mService = null; - } - - @RequiresPermission(BLUETOOTH_CONNECT) - private VolumeControlService getService(AttributionSource source) { - requireNonNull(source); - - // Cache mService because it can change while getService is called - VolumeControlService service = mService; - - if (Utils.isInstrumentationTestMode()) { - return service; - } - - if (!Utils.checkServiceAvailable(service, TAG) - || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) - || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { - return null; - } - - return service; - } - - @Override - public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { - VolumeControlService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getConnectedDevices(); - } - - @Override - public List<BluetoothDevice> getDevicesMatchingConnectionStates( - int[] states, AttributionSource source) { - VolumeControlService service = getService(source); - if (service == null) { - return Collections.emptyList(); - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - return service.getDevicesMatchingConnectionStates(states); - } - - @Override - public int getConnectionState(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - - VolumeControlService service = getService(source); - if (service == null) { - return STATE_DISCONNECTED; - } - - return service.getConnectionState(device); - } - - @Override - public boolean setConnectionPolicy( - BluetoothDevice device, int connectionPolicy, AttributionSource source) { - requireNonNull(device); - - VolumeControlService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.setConnectionPolicy(device, connectionPolicy); - } - - @Override - public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - - VolumeControlService service = getService(source); - if (service == null) { - return CONNECTION_POLICY_UNKNOWN; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getConnectionPolicy(device); - } - - @Override - public boolean isVolumeOffsetAvailable(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - - VolumeControlService service = getService(source); - if (service == null) { - return false; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.isVolumeOffsetAvailable(device); - } - - @Override - public int getNumberOfVolumeOffsetInstances( - BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - - VolumeControlService service = getService(source); - if (service == null) { - return 0; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - return service.getNumberOfVolumeOffsetInstances(device); - } - - @Override - public void setVolumeOffset( - BluetoothDevice device, - int instanceId, - int volumeOffset, - AttributionSource source) { - requireNonNull(device); - - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.setVolumeOffset(device, instanceId, volumeOffset); - } - - @Override - public void setDeviceVolume( - BluetoothDevice device, int volume, boolean isGroupOp, AttributionSource source) { - requireNonNull(device); - - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - service.setDeviceVolume(device, volume, isGroupOp); - } - - @Override - public void setGroupVolume(int groupId, int volume, AttributionSource source) { - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.setGroupVolume(groupId, volume); - } - - @Override - public int getGroupVolume(int groupId, AttributionSource source) { - VolumeControlService service = getService(source); - if (service == null) { - return 0; - } - - return service.getGroupVolume(groupId); - } - - @Override - public void setGroupActive(int groupId, boolean active, AttributionSource source) { - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.setGroupActive(groupId, active); - } - - @Override - public void mute(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.mute(device); - } - - @Override - public void muteGroup(int groupId, AttributionSource source) { - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.muteGroup(groupId); - } - - @Override - public void unmute(BluetoothDevice device, AttributionSource source) { - requireNonNull(device); - - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.unmute(device); - } - - @Override - public void unmuteGroup(int groupId, AttributionSource source) { - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.unmuteGroup(groupId); - } - - private static void postAndWait(Handler handler, Runnable runnable) { - FutureTask<Void> task = new FutureTask(Executors.callable(runnable)); - - handler.post(task); - try { - task.get(1, TimeUnit.SECONDS); - } catch (TimeoutException | InterruptedException e) { - SneakyThrow.sneakyThrow(e); - } catch (ExecutionException e) { - SneakyThrow.sneakyThrow(e.getCause()); - } - } - - @Override - public void registerCallback( - IBluetoothVolumeControlCallback callback, AttributionSource source) { - requireNonNull(callback); - - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - postAndWait(service.mHandler, () -> service.registerCallback(callback)); - } - - @Override - public void unregisterCallback( - IBluetoothVolumeControlCallback callback, AttributionSource source) { - requireNonNull(callback); - - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - postAndWait(service.mHandler, () -> service.unregisterCallback(callback)); - } - - @Override - public void notifyNewRegisteredCallback( - IBluetoothVolumeControlCallback callback, AttributionSource source) { - requireNonNull(callback); - - VolumeControlService service = getService(source); - if (service == null) { - return; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - postAndWait(service.mHandler, () -> service.notifyNewRegisteredCallback(callback)); - } - - private static void validateBluetoothDevice(BluetoothDevice device) { - requireNonNull(device); - String address = device.getAddress(); - if (!BluetoothAdapter.checkBluetoothAddress(address)) { - throw new IllegalArgumentException("Invalid device address: " + address); - } - } - - @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) - private <R> R aicsWrapper( - AttributionSource source, - BluetoothDevice device, - Function<VolumeControlInputDescriptor, R> fn, - R defaultValue) { - validateBluetoothDevice(device); - - VolumeControlService service = getService(source); - if (service == null) { - return defaultValue; - } - - service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); - - VolumeControlInputDescriptor inputs = service.mAudioInputs.get(device); - if (inputs == null) { - Log.w(TAG, "No audio inputs for " + device); - return defaultValue; - } - - return fn.apply(inputs); - } - - @Override - public int getNumberOfAudioInputControlServices( - AttributionSource source, BluetoothDevice device) { - validateBluetoothDevice(device); - Log.d(TAG, "getNumberOfAudioInputControlServices(" + device + ")"); - return aicsWrapper(source, device, i -> i.size(), 0); - } - - @Override - public void registerAudioInputControlCallback( - AttributionSource source, - BluetoothDevice device, - int instanceId, - IAudioInputCallback callback) { - requireNonNull(callback); - Log.d( - TAG, - "registerAudioInputControlCallback(" - + (device + ", " + instanceId + ", " + callback) - + ")"); - aicsWrapper( - source, - device, - i -> { - i.registerCallback(instanceId, callback); - return null; - }, - null); - } - - @Override - public void unregisterAudioInputControlCallback( - AttributionSource source, - BluetoothDevice device, - int instanceId, - IAudioInputCallback callback) { - requireNonNull(callback); - Log.d( - TAG, - "unregisterAudioInputControlCallback(" - + (device + ", " + instanceId + ", " + callback) - + ")"); - aicsWrapper( - source, - device, - i -> { - i.unregisterCallback(instanceId, callback); - return null; - }, - null); - } - - @Override - public int getAudioInputGainSettingUnit( - AttributionSource source, BluetoothDevice device, int instanceId) { - Log.d(TAG, "getAudioInputGainSettingUnit(" + device + ", " + instanceId + ")"); - return aicsWrapper(source, device, i -> i.getGainSettingUnit(instanceId), 0); - } - - @Override - public int getAudioInputGainSettingMin( - AttributionSource source, BluetoothDevice device, int instanceId) { - Log.d(TAG, "getAudioInputGainSettingMin(" + device + ", " + instanceId + ")"); - return aicsWrapper(source, device, i -> i.getGainSettingMin(instanceId), 0); - } - - @Override - public int getAudioInputGainSettingMax( - AttributionSource source, BluetoothDevice device, int instanceId) { - Log.d(TAG, "getAudioInputGainSettingMax(" + device + ", " + instanceId + ")"); - return aicsWrapper(source, device, i -> i.getGainSettingMax(instanceId), 0); - } - - @Override - public String getAudioInputDescription( - AttributionSource source, BluetoothDevice device, int instanceId) { - Log.d(TAG, "getAudioInputDescription(" + device + ", " + instanceId + ")"); - return aicsWrapper(source, device, i -> i.getDescription(instanceId), ""); - } - - @Override - public boolean isAudioInputDescriptionWritable( - AttributionSource source, BluetoothDevice device, int instanceId) { - Log.d(TAG, "isAudioInputDescriptionWritable(" + device + ", " + instanceId + ")"); - return aicsWrapper(source, device, i -> i.isDescriptionWritable(instanceId), false); - } - - @Override - public boolean setAudioInputDescription( - AttributionSource source, - BluetoothDevice device, - int instanceId, - String description) { - requireNonNull(description); - Log.d(TAG, "setAudioInputDescription(" + device + ", " + instanceId + ")"); - return aicsWrapper( - source, device, i -> i.setDescription(instanceId, description), false); - } - - @Override - public @AudioInputStatus int getAudioInputStatus( - AttributionSource source, BluetoothDevice device, int instanceId) { - Log.d(TAG, "getAudioInputStatus(" + device + ", " + instanceId + ")"); - return aicsWrapper( - source, - device, - i -> i.getStatus(instanceId), - (int) bluetooth.constants.aics.AudioInputStatus.INACTIVE); - } - - @Override - public @AudioInputType int getAudioInputType( - AttributionSource source, BluetoothDevice device, int instanceId) { - Log.d(TAG, "getAudioInputType(" + device + ", " + instanceId + ")"); - return aicsWrapper( - source, - device, - i -> i.getType(instanceId), - bluetooth.constants.AudioInputType.UNSPECIFIED); - } - - @Override - public int getAudioInputGainSetting( - AttributionSource source, BluetoothDevice device, int instanceId) { - Log.d(TAG, "getAudioInputGainSetting(" + device + ", " + instanceId + ")"); - return aicsWrapper(source, device, i -> i.getGainSetting(instanceId), 0); - } - - @Override - public boolean setAudioInputGainSetting( - AttributionSource source, BluetoothDevice device, int instanceId, int gainSetting) { - Log.d(TAG, "setAudioInputGainSetting(" + device + ", " + instanceId + ")"); - return aicsWrapper( - source, device, i -> i.setGainSetting(instanceId, gainSetting), false); - } - - @Override - public @GainMode int getAudioInputGainMode( - AttributionSource source, BluetoothDevice device, int instanceId) { - Log.d(TAG, "getAudioInputGainMode(" + device + ", " + instanceId + ")"); - return aicsWrapper( - source, - device, - i -> i.getGainMode(instanceId), - (int) bluetooth.constants.aics.GainMode.AUTOMATIC_ONLY); - } - - @Override - public boolean setAudioInputGainMode( - AttributionSource source, - BluetoothDevice device, - int instanceId, - @GainMode int gainMode) { - Log.d(TAG, "setAudioInputGainMode(" + device + ", " + instanceId + ")"); - return aicsWrapper(source, device, i -> i.setGainMode(instanceId, gainMode), false); - } - - @Override - public @Mute int getAudioInputMute( - AttributionSource source, BluetoothDevice device, int instanceId) { - Log.d(TAG, "getAudioInputMute(" + device + ", " + instanceId + ")"); - return aicsWrapper( - source, - device, - i -> i.getMute(instanceId), - (int) bluetooth.constants.aics.Mute.DISABLED); - } - - @Override - public boolean setAudioInputMute( - AttributionSource source, BluetoothDevice device, int instanceId, @Mute int mute) { - Log.d(TAG, "setAudioInputMute(" + device + ", " + instanceId + ")"); - return aicsWrapper(source, device, i -> i.setMute(instanceId, mute), false); - } - } - @Override public void dump(StringBuilder sb) { super.dump(sb); diff --git a/android/app/src/com/android/bluetooth/vc/VolumeControlServiceBinder.java b/android/app/src/com/android/bluetooth/vc/VolumeControlServiceBinder.java new file mode 100644 index 0000000000..7438ab14cd --- /dev/null +++ b/android/app/src/com/android/bluetooth/vc/VolumeControlServiceBinder.java @@ -0,0 +1,528 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.vc; + +import static android.Manifest.permission.BLUETOOTH_CONNECT; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import static java.util.Objects.requireNonNull; + +import android.annotation.RequiresPermission; +import android.bluetooth.AudioInputControl.AudioInputStatus; +import android.bluetooth.AudioInputControl.AudioInputType; +import android.bluetooth.AudioInputControl.GainMode; +import android.bluetooth.AudioInputControl.Mute; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IAudioInputCallback; +import android.bluetooth.IBluetoothVolumeControl; +import android.bluetooth.IBluetoothVolumeControlCallback; +import android.content.AttributionSource; +import android.os.Handler; +import android.util.Log; + +import com.android.bluetooth.Utils; +import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; +import com.android.internal.annotations.VisibleForTesting; + +import libcore.util.SneakyThrow; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Function; + +class VolumeControlServiceBinder extends IBluetoothVolumeControl.Stub + implements IProfileServiceBinder { + private static final String TAG = VolumeControlServiceBinder.class.getSimpleName(); + + @VisibleForTesting boolean mIsTesting = false; + private VolumeControlService mService; + + VolumeControlServiceBinder(VolumeControlService svc) { + mService = svc; + } + + @Override + public void cleanup() { + mService = null; + } + + @RequiresPermission(BLUETOOTH_CONNECT) + private VolumeControlService getService(AttributionSource source) { + requireNonNull(source); + + VolumeControlService service = mService; + + if (Utils.isInstrumentationTestMode()) { + return service; + } + + if (!Utils.checkServiceAvailable(service, TAG) + || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG) + || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) { + return null; + } + + return service; + } + + @Override + public List<BluetoothDevice> getConnectedDevices(AttributionSource source) { + VolumeControlService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectedDevices(); + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates( + int[] states, AttributionSource source) { + VolumeControlService service = getService(source); + if (service == null) { + return Collections.emptyList(); + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getDevicesMatchingConnectionStates(states); + } + + @Override + public int getConnectionState(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + + VolumeControlService service = getService(source); + if (service == null) { + return STATE_DISCONNECTED; + } + return service.getConnectionState(device); + } + + @Override + public boolean setConnectionPolicy( + BluetoothDevice device, int connectionPolicy, AttributionSource source) { + requireNonNull(device); + + VolumeControlService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.setConnectionPolicy(device, connectionPolicy); + } + + @Override + public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + + VolumeControlService service = getService(source); + if (service == null) { + return CONNECTION_POLICY_UNKNOWN; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getConnectionPolicy(device); + } + + @Override + public boolean isVolumeOffsetAvailable(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + + VolumeControlService service = getService(source); + if (service == null) { + return false; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.isVolumeOffsetAvailable(device); + } + + @Override + public int getNumberOfVolumeOffsetInstances(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + + VolumeControlService service = getService(source); + if (service == null) { + return 0; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + return service.getNumberOfVolumeOffsetInstances(device); + } + + @Override + public void setVolumeOffset( + BluetoothDevice device, int instanceId, int volumeOffset, AttributionSource source) { + requireNonNull(device); + + VolumeControlService service = getService(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setVolumeOffset(device, instanceId, volumeOffset); + } + + @Override + public void setDeviceVolume( + BluetoothDevice device, int volume, boolean isGroupOp, AttributionSource source) { + requireNonNull(device); + + VolumeControlService service = getService(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + service.setDeviceVolume(device, volume, isGroupOp); + } + + @Override + public void setGroupVolume(int groupId, int volume, AttributionSource source) { + VolumeControlService service = getService(source); + if (service == null) { + return; + } + service.setGroupVolume(groupId, volume); + } + + @Override + public int getGroupVolume(int groupId, AttributionSource source) { + VolumeControlService service = getService(source); + if (service == null) { + return 0; + } + return service.getGroupVolume(groupId); + } + + @Override + public void setGroupActive(int groupId, boolean active, AttributionSource source) { + VolumeControlService service = getService(source); + if (service == null) { + return; + } + service.setGroupActive(groupId, active); + } + + @Override + public void mute(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + + VolumeControlService service = getService(source); + if (service == null) { + return; + } + service.mute(device); + } + + @Override + public void muteGroup(int groupId, AttributionSource source) { + VolumeControlService service = getService(source); + if (service == null) { + return; + } + service.muteGroup(groupId); + } + + @Override + public void unmute(BluetoothDevice device, AttributionSource source) { + requireNonNull(device); + + VolumeControlService service = getService(source); + if (service == null) { + return; + } + service.unmute(device); + } + + @Override + public void unmuteGroup(int groupId, AttributionSource source) { + VolumeControlService service = getService(source); + if (service == null) { + return; + } + service.unmuteGroup(groupId); + } + + private static void postAndWait(Handler handler, Runnable runnable) { + FutureTask<Void> task = new FutureTask(Executors.callable(runnable)); + + handler.post(task); + try { + task.get(1, TimeUnit.SECONDS); + } catch (TimeoutException | InterruptedException e) { + SneakyThrow.sneakyThrow(e); + } catch (ExecutionException e) { + SneakyThrow.sneakyThrow(e.getCause()); + } + } + + @Override + public void registerCallback( + IBluetoothVolumeControlCallback callback, AttributionSource source) { + requireNonNull(callback); + + VolumeControlService service = getService(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + postAndWait(service.getHandler(), () -> service.registerCallback(callback)); + } + + @Override + public void unregisterCallback( + IBluetoothVolumeControlCallback callback, AttributionSource source) { + requireNonNull(callback); + + VolumeControlService service = getService(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + postAndWait(service.getHandler(), () -> service.unregisterCallback(callback)); + } + + @Override + public void notifyNewRegisteredCallback( + IBluetoothVolumeControlCallback callback, AttributionSource source) { + requireNonNull(callback); + + VolumeControlService service = getService(source); + if (service == null) { + return; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + postAndWait(service.getHandler(), () -> service.notifyNewRegisteredCallback(callback)); + } + + private static void validateBluetoothDevice(BluetoothDevice device) { + requireNonNull(device); + String address = device.getAddress(); + if (!BluetoothAdapter.checkBluetoothAddress(address)) { + throw new IllegalArgumentException("Invalid device address: " + address); + } + } + + @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) + private <R> R aicsWrapper( + AttributionSource source, + BluetoothDevice device, + Function<VolumeControlInputDescriptor, R> fn, + R defaultValue) { + validateBluetoothDevice(device); + + VolumeControlService service = getService(source); + if (service == null) { + return defaultValue; + } + + service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); + + VolumeControlInputDescriptor inputs = service.getAudioInputs().get(device); + if (inputs == null) { + Log.w(TAG, "No audio inputs for " + device); + return defaultValue; + } + + return fn.apply(inputs); + } + + @Override + public int getNumberOfAudioInputControlServices( + AttributionSource source, BluetoothDevice device) { + validateBluetoothDevice(device); + Log.d(TAG, "getNumberOfAudioInputControlServices(" + device + ")"); + return aicsWrapper(source, device, i -> i.size(), 0); + } + + @Override + public void registerAudioInputControlCallback( + AttributionSource source, + BluetoothDevice device, + int instanceId, + IAudioInputCallback callback) { + requireNonNull(callback); + Log.d( + TAG, + "registerAudioInputControlCallback(" + + (device + ", " + instanceId + ", " + callback) + + ")"); + aicsWrapper( + source, + device, + i -> { + i.registerCallback(instanceId, callback); + return null; + }, + null); + } + + @Override + public void unregisterAudioInputControlCallback( + AttributionSource source, + BluetoothDevice device, + int instanceId, + IAudioInputCallback callback) { + requireNonNull(callback); + Log.d( + TAG, + "unregisterAudioInputControlCallback(" + + (device + ", " + instanceId + ", " + callback) + + ")"); + aicsWrapper( + source, + device, + i -> { + i.unregisterCallback(instanceId, callback); + return null; + }, + null); + } + + @Override + public int getAudioInputGainSettingUnit( + AttributionSource source, BluetoothDevice device, int instanceId) { + Log.d(TAG, "getAudioInputGainSettingUnit(" + device + ", " + instanceId + ")"); + return aicsWrapper(source, device, i -> i.getGainSettingUnit(instanceId), 0); + } + + @Override + public int getAudioInputGainSettingMin( + AttributionSource source, BluetoothDevice device, int instanceId) { + Log.d(TAG, "getAudioInputGainSettingMin(" + device + ", " + instanceId + ")"); + return aicsWrapper(source, device, i -> i.getGainSettingMin(instanceId), 0); + } + + @Override + public int getAudioInputGainSettingMax( + AttributionSource source, BluetoothDevice device, int instanceId) { + Log.d(TAG, "getAudioInputGainSettingMax(" + device + ", " + instanceId + ")"); + return aicsWrapper(source, device, i -> i.getGainSettingMax(instanceId), 0); + } + + @Override + public String getAudioInputDescription( + AttributionSource source, BluetoothDevice device, int instanceId) { + Log.d(TAG, "getAudioInputDescription(" + device + ", " + instanceId + ")"); + return aicsWrapper(source, device, i -> i.getDescription(instanceId), ""); + } + + @Override + public boolean isAudioInputDescriptionWritable( + AttributionSource source, BluetoothDevice device, int instanceId) { + Log.d(TAG, "isAudioInputDescriptionWritable(" + device + ", " + instanceId + ")"); + return aicsWrapper(source, device, i -> i.isDescriptionWritable(instanceId), false); + } + + @Override + public boolean setAudioInputDescription( + AttributionSource source, BluetoothDevice device, int instanceId, String description) { + requireNonNull(description); + Log.d(TAG, "setAudioInputDescription(" + device + ", " + instanceId + ")"); + return aicsWrapper(source, device, i -> i.setDescription(instanceId, description), false); + } + + @Override + public @AudioInputStatus int getAudioInputStatus( + AttributionSource source, BluetoothDevice device, int instanceId) { + Log.d(TAG, "getAudioInputStatus(" + device + ", " + instanceId + ")"); + return aicsWrapper( + source, + device, + i -> i.getStatus(instanceId), + (int) bluetooth.constants.aics.AudioInputStatus.INACTIVE); + } + + @Override + public @AudioInputType int getAudioInputType( + AttributionSource source, BluetoothDevice device, int instanceId) { + Log.d(TAG, "getAudioInputType(" + device + ", " + instanceId + ")"); + return aicsWrapper( + source, + device, + i -> i.getType(instanceId), + bluetooth.constants.AudioInputType.UNSPECIFIED); + } + + @Override + public int getAudioInputGainSetting( + AttributionSource source, BluetoothDevice device, int instanceId) { + Log.d(TAG, "getAudioInputGainSetting(" + device + ", " + instanceId + ")"); + return aicsWrapper(source, device, i -> i.getGainSetting(instanceId), 0); + } + + @Override + public boolean setAudioInputGainSetting( + AttributionSource source, BluetoothDevice device, int instanceId, int gainSetting) { + Log.d(TAG, "setAudioInputGainSetting(" + device + ", " + instanceId + ")"); + return aicsWrapper(source, device, i -> i.setGainSetting(instanceId, gainSetting), false); + } + + @Override + public @GainMode int getAudioInputGainMode( + AttributionSource source, BluetoothDevice device, int instanceId) { + Log.d(TAG, "getAudioInputGainMode(" + device + ", " + instanceId + ")"); + return aicsWrapper( + source, + device, + i -> i.getGainMode(instanceId), + (int) bluetooth.constants.aics.GainMode.AUTOMATIC_ONLY); + } + + @Override + public boolean setAudioInputGainMode( + AttributionSource source, + BluetoothDevice device, + int instanceId, + @GainMode int gainMode) { + Log.d(TAG, "setAudioInputGainMode(" + device + ", " + instanceId + ")"); + return aicsWrapper(source, device, i -> i.setGainMode(instanceId, gainMode), false); + } + + @Override + public @Mute int getAudioInputMute( + AttributionSource source, BluetoothDevice device, int instanceId) { + Log.d(TAG, "getAudioInputMute(" + device + ", " + instanceId + ")"); + return aicsWrapper( + source, + device, + i -> i.getMute(instanceId), + (int) bluetooth.constants.aics.Mute.DISABLED); + } + + @Override + public boolean setAudioInputMute( + AttributionSource source, BluetoothDevice device, int instanceId, @Mute int mute) { + Log.d(TAG, "setAudioInputMute(" + device + ", " + instanceId + ")"); + return aicsWrapper(source, device, i -> i.setMute(instanceId, mute), false); + } +} diff --git a/android/app/tests/OWNERS b/android/app/tests/OWNERS deleted file mode 100644 index ecd59038a1..0000000000 --- a/android/app/tests/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_automotive diff --git a/android/app/tests/instrumentation/com/android/bluetooth/opp/BluetoothOppLauncherActivityTest.java b/android/app/tests/instrumentation/com/android/bluetooth/opp/BluetoothOppLauncherActivityTest.java index fd9531105b..7bb7bbfbc3 100644 --- a/android/app/tests/instrumentation/com/android/bluetooth/opp/BluetoothOppLauncherActivityTest.java +++ b/android/app/tests/instrumentation/com/android/bluetooth/opp/BluetoothOppLauncherActivityTest.java @@ -46,6 +46,7 @@ import android.net.Uri; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; +import android.provider.Settings; import android.sysprop.BluetoothProperties; import androidx.lifecycle.Lifecycle; @@ -382,6 +383,30 @@ public class BluetoothOppLauncherActivityTest { assertThat(argument.getValue().getData()).isEqualTo(Uri.EMPTY); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_SEND_OPP_DEVICE_PICKER_EXTRA_INTENT) + public void onCreate_withActionSend_grantUriPermissionToNearbyComponent() { + doReturn(true).when(mMethodProxy).bluetoothAdapterIsEnabled(any()); + doReturn(PackageManager.PERMISSION_GRANTED) + .when(mMethodProxy) + .componentCallerCheckContentUriPermission(any(), any(), anyInt()); + String uriString = "content://test.provider/1"; + Settings.Secure.putString( + mTargetContext.getContentResolver(), + "nearby_sharing_component", + "com.example/.BComponent"); + + ActivityScenario<BluetoothOppLauncherActivity> unused = + ActivityScenario.launch(createSendIntent(uriString)); + + verify(mMethodProxy) + .grantUriPermission( + any(), + eq("com.example"), + eq(Uri.parse(uriString)), + eq(Intent.FLAG_GRANT_READ_URI_PERMISSION)); + } + @Ignore("b/263724420") @Test public void launchDevicePicker_bluetoothNotEnabled_launchEnableActivity() throws Exception { diff --git a/android/app/tests/unit/Android.bp b/android/app/tests/unit/Android.bp index 01d195cc43..6bf4f72d9f 100644 --- a/android/app/tests/unit/Android.bp +++ b/android/app/tests/unit/Android.bp @@ -35,6 +35,7 @@ android_test { "androidx.room_room-runtime", "androidx.room_room-testing", "androidx.test.espresso.intents", + "androidx.test.ext.junit", "androidx.test.ext.truth", "androidx.test.rules", "androidx.test.uiautomator_uiautomator", @@ -45,6 +46,7 @@ android_test { "gson", "guava-android-testlib", "mmslib", + "mockito-kotlin2", "mockito-target-extended", "modules-utils-handlerexecutor", "platform-parametric-runner-lib", @@ -61,10 +63,13 @@ android_test { jarjar_rules: ":bluetooth-jarjar-rules", asset_dirs: ["src/com/android/bluetooth/btservice/storage/schemas"], - // Include all test java files. - srcs: ["src/**/*.java"], + // Include all test java and kotlin files. + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], jacoco: { - include_filter: ["android.bluetooth.*"], + include_filter: ["com.android.bluetooth.*"], exclude_filter: [], }, diff --git a/android/app/tests/unit/src/com/android/bluetooth/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/OWNERS deleted file mode 100644 index 621eaef441..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# MessageQueue-related classes -per-file TestLooper.java = mfasheh@google.com, shayba@google.com
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceBinderTest.java index 23e7a5ed1c..65d00773ba 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceBinderTest.java @@ -36,15 +36,20 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.platform.test.flag.junit.SetFlagsRule; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; +/** Test cases for {@link A2dpServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) public class A2dpServiceBinderTest { - private static final AttributionSource sSource = new AttributionSource.Builder(0).build(); - private static final BluetoothDevice sDevice = getTestDevice(0); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -53,7 +58,10 @@ public class A2dpServiceBinderTest { @Mock private A2dpService mA2dpService; @Mock private PackageManager mPackageManager; - private A2dpService.BluetoothA2dpBinder mBinder; + private final AttributionSource sSource = new AttributionSource.Builder(0).build(); + private final BluetoothDevice sDevice = getTestDevice(0); + + private A2dpServiceBinder mBinder; @Before public void setUp() throws Exception { @@ -62,7 +70,7 @@ public class A2dpServiceBinderTest { appInfo.targetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; doReturn(appInfo).when(mPackageManager).getApplicationInfo(any(), anyInt()); - mBinder = new A2dpService.BluetoothA2dpBinder(mA2dpService); + mBinder = new A2dpServiceBinder(mA2dpService); } @After diff --git a/android/app/tests/unit/src/com/android/bluetooth/a2dpsink/A2dpSinkServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/a2dpsink/A2dpSinkServiceBinderTest.java index aad4f1019a..6f7723caa9 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/a2dpsink/A2dpSinkServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/a2dpsink/A2dpSinkServiceBinderTest.java @@ -27,21 +27,29 @@ import static org.mockito.Mockito.verify; import android.bluetooth.BluetoothDevice; import android.content.AttributionSource; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; +/** Test cases for {@link A2dpSinkServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) public class A2dpSinkServiceBinderTest { + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private A2dpSinkService mService; - private A2dpSinkService.A2dpSinkServiceBinder mBinder; + private A2dpSinkServiceBinder mBinder; @Before public void setUp() throws Exception { - mBinder = new A2dpSinkService.A2dpSinkServiceBinder(mService); + mBinder = new A2dpSinkServiceBinder(mService); } @After diff --git a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerServiceBinderTest.java index 2cbd8f356a..c4bc5dad1a 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerServiceBinderTest.java @@ -24,6 +24,7 @@ import static com.android.bluetooth.TestUtils.getTestDevice; import static org.mockito.Mockito.verify; import android.bluetooth.BluetoothDevice; +import android.content.AttributionSource; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -34,52 +35,53 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +/** Test cases for {@link AvrcpControllerServiceBinder} */ @SmallTest @RunWith(AndroidJUnit4.class) public class AvrcpControllerServiceBinderTest { + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private AvrcpControllerService mService; + private final AttributionSource mAttributionSource = new AttributionSource.Builder(1).build(); private final BluetoothDevice mDevice = getTestDevice(49); - AvrcpControllerService.AvrcpControllerServiceBinder mBinder; + private AvrcpControllerServiceBinder mBinder; @Before public void setUp() throws Exception { - mBinder = new AvrcpControllerService.AvrcpControllerServiceBinder(mService); + mBinder = new AvrcpControllerServiceBinder(mService); } @Test public void getConnectedDevices_callsServiceMethod() { - mBinder.getConnectedDevices(null); - + mBinder.getConnectedDevices(mAttributionSource); verify(mService).getConnectedDevices(); } @Test public void getDevicesMatchingConnectionStates_callsServiceMethod() { int[] states = new int[] {STATE_CONNECTED}; - mBinder.getDevicesMatchingConnectionStates(states, null); + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); verify(mService).getDevicesMatchingConnectionStates(states); } @Test public void getConnectionState_callsServiceMethod() { - mBinder.getConnectionState(mDevice, null); - + mBinder.getConnectionState(mDevice, mAttributionSource); verify(mService).getConnectionState(mDevice); } @Test public void sendGroupNavigationCmd_notImplemented_doesNothing() { - mBinder.sendGroupNavigationCmd(mDevice, 1, 2, null); + mBinder.sendGroupNavigationCmd(mDevice, 1, 2, mAttributionSource); } @Test public void getPlayerSettings_notImplemented_doesNothing() { - mBinder.getPlayerSettings(mDevice, null); + mBinder.getPlayerSettings(mDevice, mAttributionSource); } @Test diff --git a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BleBroadcastAssistantBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceBinderTest.java index ae402d7d0f..584f0cdeea 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BleBroadcastAssistantBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceBinderTest.java @@ -36,21 +36,24 @@ import android.bluetooth.IBluetoothLeBroadcastAssistantCallback; import android.bluetooth.le.ScanFilter; import android.content.AttributionSource; +import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.Mockito; import java.util.Collections; import java.util.List; -@RunWith(JUnit4.class) -public class BleBroadcastAssistantBinderTest { +/** Test cases for {@link BassClientServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class BassClientServiceBinderTest { @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @@ -64,17 +67,16 @@ public class BleBroadcastAssistantBinderTest { @Mock private BassClientService mService; - private BassClientService.BluetoothLeBroadcastAssistantBinder mBinder; + private BassClientServiceBinder mBinder; @Before public void setUp() { - mBinder = new BassClientService.BluetoothLeBroadcastAssistantBinder(mService); + mBinder = new BassClientServiceBinder(mService); } @Test public void cleanUp() { mBinder.cleanup(); - assertThat(mBinder.mService).isNull(); } @Test diff --git a/android/app/tests/unit/src/com/android/bluetooth/bass_client/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/bass_client/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/bass_client/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceBinderTest.java index e7fa638eea..7e143a2851 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceBinderTest.java @@ -23,42 +23,50 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.IBluetoothOobDataCallback; import android.content.AttributionSource; import android.os.ParcelUuid; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import java.io.FileDescriptor; +/** Test cases for {@link AdapterServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) public class AdapterServiceBinderTest { @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private AdapterService mService; @Mock private AdapterProperties mAdapterProperties; - private AdapterService.AdapterServiceBinder mBinder; + private AdapterServiceBinder mBinder; private AttributionSource mAttributionSource; @Before public void setUp() { - mService.mAdapterProperties = mAdapterProperties; + when(mService.getAdapterProperties()).thenReturn(mAdapterProperties); doReturn(true).when(mService).isAvailable(); doNothing().when(mService).enforceCallingOrSelfPermission(any(), any()); - mBinder = new AdapterService.AdapterServiceBinder(mService); + mBinder = new AdapterServiceBinder(mService); mAttributionSource = new AttributionSource.Builder(0).build(); } @Test public void getAddress() { mBinder.getAddress(mAttributionSource); - verify(mService.mAdapterProperties).getAddress(); + verify(mAdapterProperties).getAddress(); } @Test @@ -116,7 +124,7 @@ public class AdapterServiceBinderTest { @Test public void isActivityAndEnergyReportingSupported() { mBinder.isActivityAndEnergyReportingSupported(); - verify(mService.mAdapterProperties).isActivityAndEnergyReportingSupported(); + verify(mAdapterProperties).isActivityAndEnergyReportingSupported(); } @Test diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java index 35190708de..6c7b1ed44e 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java @@ -113,6 +113,7 @@ import java.util.Map; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; +/** Test cases for {@link AdapterService}. */ @MediumTest @RunWith(ParameterizedAndroidJunit4.class) public class AdapterServiceTest { @@ -906,10 +907,6 @@ public class AdapterServiceTest { // Create device properties RemoteDevices remoteDevices = mAdapterService.getRemoteDevices(); remoteDevices.addDeviceProperties(Utils.getBytesFromAddress((TEST_BT_ADDR_1))); - String identityAddress = mAdapterService.getIdentityAddress(TEST_BT_ADDR_1); - if (!Flags.identityAddressNullIfNotKnown()) { - assertThat(identityAddress).isEqualTo(TEST_BT_ADDR_1); - } // Trigger address consolidate callback remoteDevices.addressConsolidateCallback( @@ -917,7 +914,7 @@ public class AdapterServiceTest { Utils.getBytesFromAddress(TEST_BT_ADDR_2)); // Verify we can get correct identity address - identityAddress = mAdapterService.getIdentityAddress(TEST_BT_ADDR_1); + String identityAddress = mAdapterService.getIdentityAddress(TEST_BT_ADDR_1); assertThat(identityAddress).isEqualTo(TEST_BT_ADDR_2); assertThat(mLooper.nextMessage()).isNull(); } @@ -954,7 +951,6 @@ public class AdapterServiceTest { } @Test - @EnableFlags(Flags.FLAG_IDENTITY_ADDRESS_NULL_IF_NOT_KNOWN) public void testIdentityAddressNullIfUnknown() { BluetoothDevice device = getTestDevice(0); diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java index 1b057b3a7e..ae3db21382 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java @@ -20,12 +20,24 @@ import static com.android.bluetooth.TestUtils.getTestDevice; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + import android.bluetooth.BluetoothDevice; +import android.content.ContentResolver; +import android.provider.Settings; +import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.BluetoothMetricsProto.BluetoothRemoteDeviceInformation; +import com.android.bluetooth.BluetoothStatsLog; import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; @@ -37,9 +49,12 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.HashMap; import java.util.Map; @@ -236,6 +251,51 @@ public class MetricsLoggerTest { assertThat(mTestableMetricsLogger.logAllowlistedDeviceNameHash(1, "")).isEmpty(); } + @Test + public void testUpdateHearingDeviceActiveTime() { + BluetoothDevice bluetoothDevice = getTestDevice(0); + int day = BluetoothStatsLog.HEARING_DEVICE_ACTIVE_EVENT_REPORTED__TIME_PERIOD__DAY; + int week = BluetoothStatsLog.HEARING_DEVICE_ACTIVE_EVENT_REPORTED__TIME_PERIOD__WEEK; + int month = BluetoothStatsLog.HEARING_DEVICE_ACTIVE_EVENT_REPORTED__TIME_PERIOD__MONTH; + doReturn(ApplicationProvider.getApplicationContext().getContentResolver()) + .when(mAdapterService) + .getContentResolver(); + + // last active time is 2 days ago, should update last active day + TestableMetricsLogger logger = spy(mTestableMetricsLogger); + prepareLastActiveTimeDaysAgo(2); + logger.updateHearingDeviceActiveTime(bluetoothDevice, 1); + verify(logger).logHearingDeviceActiveEvent(any(), anyInt(), eq(day)); + verify(logger, never()).logHearingDeviceActiveEvent(any(), anyInt(), eq(week)); + verify(logger, never()).logHearingDeviceActiveEvent(any(), anyInt(), eq(month)); + + // last active time is 8 days ago, should update last active day and week + Mockito.reset(logger); + prepareLastActiveTimeDaysAgo(8); + logger.updateHearingDeviceActiveTime(bluetoothDevice, 1); + verify(logger).logHearingDeviceActiveEvent(any(), anyInt(), eq(day)); + verify(logger).logHearingDeviceActiveEvent(any(), anyInt(), eq(week)); + verify(logger, never()).logHearingDeviceActiveEvent(any(), anyInt(), eq(month)); + + // last active time is 60 days ago, should update last active day, week and month + Mockito.reset(logger); + prepareLastActiveTimeDaysAgo(60); + logger.updateHearingDeviceActiveTime(bluetoothDevice, 1); + verify(logger).logHearingDeviceActiveEvent(any(), anyInt(), eq(day)); + verify(logger).logHearingDeviceActiveEvent(any(), anyInt(), eq(week)); + verify(logger).logHearingDeviceActiveEvent(any(), anyInt(), eq(month)); + } + + private static void prepareLastActiveTimeDaysAgo(int days) { + final ContentResolver contentResolver = + ApplicationProvider.getApplicationContext().getContentResolver(); + final LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault()); + final String lastActive = now.minusDays(days).toString(); + Settings.Secure.putString(contentResolver, "last_active_day", lastActive); + Settings.Secure.putString(contentResolver, "last_active_week", lastActive); + Settings.Secure.putString(contentResolver, "last_active_month", lastActive); + } + private void initTestingBloomfilter() throws IOException { byte[] bloomfilterData = DeviceBloomfilterGenerator.hexStringToByteArray( diff --git a/android/app/tests/unit/src/com/android/bluetooth/content_profiles/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/content_profiles/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/content_profiles/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/csip/BluetoothCsisBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceBinderTest.java index 9233602c47..81adae18f4 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/csip/BluetoothCsisBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceBinderTest.java @@ -30,12 +30,20 @@ import android.bluetooth.IBluetoothCsipSetCoordinatorLockCallback; import android.content.AttributionSource; import android.os.ParcelUuid; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; -public class BluetoothCsisBinderTest { +/** Test cases for {@link CsipSetCoordinatorServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class CsipSetCoordinatorServiceBinderTest { + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private CsipSetCoordinatorService mService; @@ -43,11 +51,11 @@ public class BluetoothCsisBinderTest { private final BluetoothDevice mDevice = getTestDevice(45); private final AttributionSource mAttributionSource = new AttributionSource.Builder(1).build(); - private CsipSetCoordinatorService.BluetoothCsisBinder mBinder; + private CsipSetCoordinatorServiceBinder mBinder; @Before public void setUp() throws Exception { - mBinder = new CsipSetCoordinatorService.BluetoothCsisBinder(mService); + mBinder = new CsipSetCoordinatorServiceBinder(mService); } @Test @@ -59,6 +67,7 @@ public class BluetoothCsisBinderTest { @Test public void getDevicesMatchingConnectionStates() { int[] states = new int[] {STATE_CONNECTED}; + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); verify(mService).getDevicesMatchingConnectionStates(states); } @@ -72,6 +81,7 @@ public class BluetoothCsisBinderTest { @Test public void setConnectionPolicy() { int connectionPolicy = CONNECTION_POLICY_ALLOWED; + mBinder.setConnectionPolicy(mDevice, connectionPolicy, mAttributionSource); verify(mService).setConnectionPolicy(mDevice, connectionPolicy); } @@ -87,6 +97,7 @@ public class BluetoothCsisBinderTest { int groupId = 100; IBluetoothCsipSetCoordinatorLockCallback cb = mock(IBluetoothCsipSetCoordinatorLockCallback.class); + mBinder.lockGroup(groupId, cb, mAttributionSource); verify(mService).lockGroup(groupId, cb); } @@ -94,6 +105,7 @@ public class BluetoothCsisBinderTest { @Test public void unlockGroup() { ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); + mBinder.unlockGroup(uuid, mAttributionSource); verify(mService).unlockGroup(uuid.getUuid()); } @@ -101,6 +113,7 @@ public class BluetoothCsisBinderTest { @Test public void getAllGroupIds() { ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); + mBinder.getAllGroupIds(uuid, mAttributionSource); verify(mService).getAllGroupIds(uuid); } diff --git a/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java index ac64b097ae..72fbd125b6 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java @@ -130,7 +130,6 @@ public class CsipSetCoordinatorServiceTest { new CsipSetCoordinatorService( mAdapterService, mLooper.getLooper(), mNativeInterface, mServiceFactory); mService.setAvailable(true); - } @After diff --git a/android/app/tests/unit/src/com/android/bluetooth/csip/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/csip/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/csip/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java deleted file mode 100644 index c78c9ec6db..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2025 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bluetooth.gatt; - -import static com.android.bluetooth.TestUtils.MockitoRule; - -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import android.bluetooth.BluetoothManager; -import android.bluetooth.le.AdvertiseData; -import android.bluetooth.le.AdvertisingSetParameters; -import android.bluetooth.le.IAdvertisingSetCallback; -import android.bluetooth.le.PeriodicAdvertisingParameters; -import android.content.AttributionSource; - -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import com.android.bluetooth.btservice.AdapterService; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; - -/** Test cases for {@link AdvertiseBinder}. */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class AdvertiseBinderTest { - @Rule public final MockitoRule mMockitoRule = new MockitoRule(); - - @Mock private AdapterService mAdapterService; - @Mock private AdvertiseManager mAdvertiseManager; - - private final AttributionSource mAttributionSource = - InstrumentationRegistry.getInstrumentation() - .getTargetContext() - .getSystemService(BluetoothManager.class) - .getAdapter() - .getAttributionSource(); - private AdvertiseBinder mBinder; - - @Before - public void setUp() { - doAnswer( - invocation -> { - ((Runnable) invocation.getArgument(0)).run(); - return null; - }) - .when(mAdvertiseManager) - .doOnAdvertiseThread(any()); - mBinder = new AdvertiseBinder(mAdapterService, mAdvertiseManager); - } - - @Test - public void startAdvertisingSet() { - AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder().build(); - AdvertiseData advertiseData = new AdvertiseData.Builder().build(); - AdvertiseData scanResponse = new AdvertiseData.Builder().build(); - PeriodicAdvertisingParameters periodicParameters = - new PeriodicAdvertisingParameters.Builder().build(); - AdvertiseData periodicData = new AdvertiseData.Builder().build(); - int duration = 1; - int maxExtAdvEvents = 2; - int serverIf = 3; - IAdvertisingSetCallback callback = mock(IAdvertisingSetCallback.class); - - mBinder.startAdvertisingSet( - parameters, - advertiseData, - scanResponse, - periodicParameters, - periodicData, - duration, - maxExtAdvEvents, - serverIf, - callback, - mAttributionSource); - - verify(mAdvertiseManager) - .startAdvertisingSet( - parameters, - advertiseData, - scanResponse, - periodicParameters, - periodicData, - duration, - maxExtAdvEvents, - serverIf, - callback, - mAttributionSource); - } - - @Test - public void stopAdvertisingSet() { - IAdvertisingSetCallback callback = mock(IAdvertisingSetCallback.class); - - mBinder.stopAdvertisingSet(callback, mAttributionSource); - - verify(mAdvertiseManager).stopAdvertisingSet(callback); - } - - @Test - public void setAdvertisingData() { - int advertiserId = 1; - AdvertiseData data = new AdvertiseData.Builder().build(); - - mBinder.setAdvertisingData(advertiserId, data, mAttributionSource); - verify(mAdvertiseManager).setAdvertisingData(advertiserId, data); - } - - @Test - public void setAdvertisingParameters() { - int advertiserId = 1; - AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder().build(); - - mBinder.setAdvertisingParameters(advertiserId, parameters, mAttributionSource); - verify(mAdvertiseManager).setAdvertisingParameters(advertiserId, parameters); - } - - @Test - public void setPeriodicAdvertisingData() { - int advertiserId = 1; - AdvertiseData data = new AdvertiseData.Builder().build(); - - mBinder.setPeriodicAdvertisingData(advertiserId, data, mAttributionSource); - verify(mAdvertiseManager).setPeriodicAdvertisingData(advertiserId, data); - } - - @Test - public void setPeriodicAdvertisingEnable() { - int advertiserId = 1; - boolean enable = true; - - mBinder.setPeriodicAdvertisingEnable(advertiserId, enable, mAttributionSource); - verify(mAdvertiseManager).setPeriodicAdvertisingEnable(advertiserId, enable); - } - - @Test - public void setPeriodicAdvertisingParameters() { - int advertiserId = 1; - PeriodicAdvertisingParameters parameters = - new PeriodicAdvertisingParameters.Builder().build(); - - mBinder.setPeriodicAdvertisingParameters(advertiserId, parameters, mAttributionSource); - verify(mAdvertiseManager).setPeriodicAdvertisingParameters(advertiserId, parameters); - } - - @Test - public void setScanResponseData() { - int advertiserId = 1; - AdvertiseData data = new AdvertiseData.Builder().build(); - - mBinder.setScanResponseData(advertiserId, data, mAttributionSource); - verify(mAdvertiseManager).setScanResponseData(advertiserId, data); - } - - @Test - public void getOwnAddress() { - int advertiserId = 1; - - mBinder.getOwnAddress(advertiserId, mAttributionSource); - verify(mAdvertiseManager).getOwnAddress(advertiserId); - } - - @Test - public void enableAdvertisingSet() { - int advertiserId = 1; - boolean enable = true; - int duration = 3; - int maxExtAdvEvents = 4; - - mBinder.enableAdvertisingSet( - advertiserId, enable, duration, maxExtAdvEvents, mAttributionSource); - verify(mAdvertiseManager) - .enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents); - } - - @Test - public void cleanUp_doesNotCrash() { - mBinder.cleanup(); - } -} diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.kt b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.kt new file mode 100644 index 0000000000..6b038678f0 --- /dev/null +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.kt @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.gatt + +import android.bluetooth.BluetoothManager +import android.bluetooth.le.AdvertiseData +import android.bluetooth.le.AdvertisingSetParameters +import android.bluetooth.le.IAdvertisingSetCallback +import android.bluetooth.le.PeriodicAdvertisingParameters +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import com.android.bluetooth.TestUtils.MockitoRule +import com.android.bluetooth.btservice.AdapterService +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.kotlin.whenever + +/** Test cases for [AdvertiseBinder] */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class AdvertiseBinderTest { + + @get:Rule val mockitoRule = MockitoRule() + + @Mock private lateinit var adapterService: AdapterService + @Mock private lateinit var advertiseManager: AdvertiseManager + + private val attributionSource = + InstrumentationRegistry.getInstrumentation() + .targetContext + .getSystemService(BluetoothManager::class.java) + .adapter + .attributionSource + + private lateinit var binder: AdvertiseBinder + + @Before + fun setUp() { + doAnswer { invocation -> + (invocation.getArgument(0) as Runnable).run() + null + } + .whenever(advertiseManager) + .doOnAdvertiseThread(any()) + binder = AdvertiseBinder(adapterService, advertiseManager) + } + + @Test + fun startAdvertisingSet() { + val parameters = AdvertisingSetParameters.Builder().build() + val advertiseData = AdvertiseData.Builder().build() + val scanResponse = AdvertiseData.Builder().build() + val periodicParameters = PeriodicAdvertisingParameters.Builder().build() + val periodicData = AdvertiseData.Builder().build() + val duration = 1 + val maxExtAdvEvents = 2 + val serverIf = 3 + val callback = mock(IAdvertisingSetCallback::class.java) + + binder.startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + duration, + maxExtAdvEvents, + serverIf, + callback, + attributionSource, + ) + verify(advertiseManager) + .startAdvertisingSet( + parameters, + advertiseData, + scanResponse, + periodicParameters, + periodicData, + duration, + maxExtAdvEvents, + serverIf, + callback, + attributionSource, + ) + } + + @Test + fun stopAdvertisingSet() { + val callback = mock(IAdvertisingSetCallback::class.java) + + binder.stopAdvertisingSet(callback, attributionSource) + verify(advertiseManager).stopAdvertisingSet(callback) + } + + @Test + fun setAdvertisingData() { + val advertiserId = 1 + val data = AdvertiseData.Builder().build() + + binder.setAdvertisingData(advertiserId, data, attributionSource) + verify(advertiseManager).setAdvertisingData(advertiserId, data) + } + + @Test + fun setAdvertisingParameters() { + val advertiserId = 1 + val parameters = AdvertisingSetParameters.Builder().build() + + binder.setAdvertisingParameters(advertiserId, parameters, attributionSource) + verify(advertiseManager).setAdvertisingParameters(advertiserId, parameters) + } + + @Test + fun setPeriodicAdvertisingData() { + val advertiserId = 1 + val data = AdvertiseData.Builder().build() + + binder.setPeriodicAdvertisingData(advertiserId, data, attributionSource) + verify(advertiseManager).setPeriodicAdvertisingData(advertiserId, data) + } + + @Test + fun setPeriodicAdvertisingEnable() { + val advertiserId = 1 + val enable = true + + binder.setPeriodicAdvertisingEnable(advertiserId, enable, attributionSource) + verify(advertiseManager).setPeriodicAdvertisingEnable(advertiserId, enable) + } + + @Test + fun setPeriodicAdvertisingParameters() { + val advertiserId = 1 + val parameters = PeriodicAdvertisingParameters.Builder().build() + + binder.setPeriodicAdvertisingParameters(advertiserId, parameters, attributionSource) + verify(advertiseManager).setPeriodicAdvertisingParameters(advertiserId, parameters) + } + + @Test + fun setScanResponseData() { + val advertiserId = 1 + val data = AdvertiseData.Builder().build() + + binder.setScanResponseData(advertiserId, data, attributionSource) + verify(advertiseManager).setScanResponseData(advertiserId, data) + } + + @Test + fun getOwnAddress() { + val advertiserId = 1 + + binder.getOwnAddress(advertiserId, attributionSource) + verify(advertiseManager).getOwnAddress(advertiserId) + } + + @Test + fun enableAdvertisingSet() { + val advertiserId = 1 + val enable = true + val duration = 3 + val maxExtAdvEvents = 4 + + binder.enableAdvertisingSet( + advertiserId, + enable, + duration, + maxExtAdvEvents, + attributionSource, + ) + verify(advertiseManager) + .enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents) + } + + @Test + fun cleanup_doesNotCrash() { + binder.cleanup() + } +} diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/AppAdvertiseStatsTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/AppAdvertiseStatsTest.java index 86a26e5ad9..e2bcfb75e2 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/AppAdvertiseStatsTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/AppAdvertiseStatsTest.java @@ -305,7 +305,6 @@ public class AppAdvertiseStatsTest { } @Test - @EnableFlags(Flags.FLAG_BLE_SCAN_ADV_METRICS_REDESIGN) public void testAdvertiseCounterMetrics() { int appUid = 0; int id = 1; @@ -356,7 +355,8 @@ public class AppAdvertiseStatsTest { true, instanceCount, 0, - IMPORTANCE_FOREGROUND_SERVICE); + IMPORTANCE_FOREGROUND_SERVICE, + ""); Mockito.clearInvocations(mMetricsLogger); // Wait for adv test duration @@ -390,7 +390,8 @@ public class AppAdvertiseStatsTest { eq(true), eq(instanceCount), mAdvDurationCaptor.capture(), - eq(IMPORTANCE_FOREGROUND_SERVICE)); + eq(IMPORTANCE_FOREGROUND_SERVICE), + eq("")); long capturedAppScanDuration = mAdvDurationCaptor.getValue(); Log.d(TAG, "capturedDuration: " + capturedAppScanDuration); assertThat(capturedAppScanDuration).isAtLeast(advTestDuration); diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.java deleted file mode 100644 index a65c805a47..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2025 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bluetooth.gatt; - -import static com.android.bluetooth.TestUtils.MockitoRule; -import static com.android.bluetooth.TestUtils.getTestDevice; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothManager; -import android.bluetooth.le.DistanceMeasurementMethod; -import android.bluetooth.le.DistanceMeasurementParams; -import android.bluetooth.le.IDistanceMeasurementCallback; -import android.content.AttributionSource; -import android.os.ParcelUuid; - -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import com.android.bluetooth.btservice.AdapterService; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; - -import java.util.Collections; -import java.util.UUID; - -/** Test cases for {@link DistanceMeasurementBinder}. */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class DistanceMeasurementBinderTest { - @Rule public final MockitoRule mMockitoRule = new MockitoRule(); - - @Mock private DistanceMeasurementManager mDistanceMeasurementManager; - @Mock private AdapterService mAdapterService; - - private final AttributionSource mAttributionSource = - InstrumentationRegistry.getInstrumentation() - .getTargetContext() - .getSystemService(BluetoothManager.class) - .getAdapter() - .getAttributionSource(); - - private DistanceMeasurementBinder mBinder; - - @Before - public void setUp() throws Throwable { - mBinder = new DistanceMeasurementBinder(mAdapterService, mDistanceMeasurementManager); - when(mDistanceMeasurementManager.getSupportedDistanceMeasurementMethods()) - .thenReturn(Collections.emptyList()); - when(mDistanceMeasurementManager.runOnDistanceMeasurementThreadAndWaitForResult(any())) - .thenAnswer( - invocationOnMock -> { - DistanceMeasurementManager.GetResultTask task = - invocationOnMock.getArgument(0); - return task.getResult(); - }); - doAnswer( - invocation -> { - ((Runnable) (invocation.getArgument(0))).run(); - return null; - }) - .when(mDistanceMeasurementManager) - .postOnDistanceMeasurementThread(any()); - } - - @Test - public void getSupportedDistanceMeasurementMethods() { - mBinder.getSupportedDistanceMeasurementMethods(mAttributionSource); - verify(mDistanceMeasurementManager).getSupportedDistanceMeasurementMethods(); - } - - @Test - public void startDistanceMeasurement() { - UUID uuid = UUID.randomUUID(); - BluetoothDevice device = getTestDevice(3); - DistanceMeasurementParams params = - new DistanceMeasurementParams.Builder(device) - .setDurationSeconds(123) - .setFrequency(DistanceMeasurementParams.REPORT_FREQUENCY_LOW) - .build(); - IDistanceMeasurementCallback callback = mock(IDistanceMeasurementCallback.class); - mBinder.startDistanceMeasurement( - new ParcelUuid(uuid), params, callback, mAttributionSource); - verify(mDistanceMeasurementManager).startDistanceMeasurement(uuid, params, callback); - } - - @Test - public void stopDistanceMeasurement() { - UUID uuid = UUID.randomUUID(); - BluetoothDevice device = getTestDevice(3); - int method = DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_RSSI; - mBinder.stopDistanceMeasurement(new ParcelUuid(uuid), device, method, mAttributionSource); - verify(mDistanceMeasurementManager).stopDistanceMeasurement(uuid, device, method, false); - } -} diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.kt b/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.kt new file mode 100644 index 0000000000..b20eda9a17 --- /dev/null +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.kt @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.gatt + +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothManager +import android.bluetooth.le.DistanceMeasurementMethod +import android.bluetooth.le.DistanceMeasurementParams +import android.bluetooth.le.IDistanceMeasurementCallback +import android.os.ParcelUuid +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import com.android.bluetooth.TestUtils.MockitoRule +import com.android.bluetooth.TestUtils.getTestDevice +import com.android.bluetooth.btservice.AdapterService +import com.android.bluetooth.gatt.DistanceMeasurementManager.GetResultTask +import java.util.UUID +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.kotlin.whenever + +/** Test cases for [DistanceMeasurementBinder] */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class DistanceMeasurementBinderTest { + + @get:Rule val mockitoRule = MockitoRule() + + @Mock private lateinit var distanceMeasurementManager: DistanceMeasurementManager + @Mock private lateinit var adapterService: AdapterService + + private val attributionSource = + InstrumentationRegistry.getInstrumentation() + .targetContext + .getSystemService(BluetoothManager::class.java) + .adapter + .attributionSource + + private lateinit var binder: DistanceMeasurementBinder + + @Before + fun setUp() { + binder = DistanceMeasurementBinder(adapterService, distanceMeasurementManager) + doReturn(emptyList<DistanceMeasurementMethod>()) + .whenever(distanceMeasurementManager) + .getSupportedDistanceMeasurementMethods() + doAnswer { invocationOnMock -> + val task = invocationOnMock.getArgument<GetResultTask<*>>(0) + task.result + } + .whenever(distanceMeasurementManager) + .runOnDistanceMeasurementThreadAndWaitForResult(any<GetResultTask<*>>()) + doAnswer { invocation -> + (invocation.getArgument(0) as Runnable).run() + null + } + .whenever(distanceMeasurementManager) + .postOnDistanceMeasurementThread(any()) + } + + @Test + fun getSupportedDistanceMeasurementMethods() { + binder.getSupportedDistanceMeasurementMethods(attributionSource) + verify(distanceMeasurementManager).supportedDistanceMeasurementMethods + } + + @Test + fun startDistanceMeasurement() { + val uuid = UUID.randomUUID() + val device: BluetoothDevice = getTestDevice(3) + val params = + DistanceMeasurementParams.Builder(device) + .setDurationSeconds(123) + .setFrequency(DistanceMeasurementParams.REPORT_FREQUENCY_LOW) + .build() + val callback = mock(IDistanceMeasurementCallback::class.java) + binder.startDistanceMeasurement(ParcelUuid(uuid), params, callback, attributionSource) + verify(distanceMeasurementManager).startDistanceMeasurement(uuid, params, callback) + } + + @Test + fun stopDistanceMeasurement() { + val uuid = UUID.randomUUID() + val device: BluetoothDevice = getTestDevice(3) + val method = DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_RSSI + binder.stopDistanceMeasurement(ParcelUuid(uuid), device, method, attributionSource) + verify(distanceMeasurementManager).stopDistanceMeasurement(uuid, device, method, false) + } +} diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java index 36e96f6007..f9bb1d556d 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java @@ -42,6 +42,7 @@ import org.mockito.Mock; import java.util.UUID; +/** Test cases for {@link GattServiceBinder} */ @SmallTest @RunWith(AndroidJUnit4.class) public class GattServiceBinderTest { @@ -53,13 +54,12 @@ public class GattServiceBinderTest { @Mock private GattService mService; private AttributionSource mAttributionSource; - - private GattService.BluetoothGattBinder mBinder; + private GattServiceBinder mBinder; @Before public void setUp() throws Exception { when(mService.isAvailable()).thenReturn(true); - mBinder = new GattService.BluetoothGattBinder(mService); + mBinder = new GattServiceBinder(mService); mAttributionSource = new AttributionSource.Builder(1).build(); } @@ -68,7 +68,6 @@ public class GattServiceBinderTest { int[] states = new int[] {STATE_CONNECTED}; mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); - verify(mService).getDevicesMatchingConnectionStates(states, mAttributionSource); } @@ -79,7 +78,6 @@ public class GattServiceBinderTest { boolean eattSupport = true; mBinder.registerClient(new ParcelUuid(uuid), callback, eattSupport, mAttributionSource); - verify(mService).registerClient(uuid, callback, eattSupport, mAttributionSource); } @@ -88,7 +86,6 @@ public class GattServiceBinderTest { int clientIf = 3; mBinder.unregisterClient(clientIf, mAttributionSource); - verify(mService) .unregisterClient( clientIf, @@ -115,7 +112,6 @@ public class GattServiceBinderTest { opportunistic, phy, mAttributionSource); - verify(mService) .clientConnect( clientIf, @@ -134,7 +130,6 @@ public class GattServiceBinderTest { String address = REMOTE_DEVICE_ADDRESS; mBinder.clientDisconnect(clientIf, address, mAttributionSource); - verify(mService).clientDisconnect(clientIf, address, mAttributionSource); } @@ -148,7 +143,6 @@ public class GattServiceBinderTest { mBinder.clientSetPreferredPhy( clientIf, address, txPhy, rxPhy, phyOptions, mAttributionSource); - verify(mService) .clientSetPreferredPhy( clientIf, address, txPhy, rxPhy, phyOptions, mAttributionSource); @@ -160,7 +154,6 @@ public class GattServiceBinderTest { String address = REMOTE_DEVICE_ADDRESS; mBinder.clientReadPhy(clientIf, address, mAttributionSource); - verify(mService).clientReadPhy(clientIf, address, mAttributionSource); } @@ -170,7 +163,6 @@ public class GattServiceBinderTest { String address = REMOTE_DEVICE_ADDRESS; mBinder.refreshDevice(clientIf, address, mAttributionSource); - verify(mService).refreshDevice(clientIf, address, mAttributionSource); } @@ -180,7 +172,6 @@ public class GattServiceBinderTest { String address = REMOTE_DEVICE_ADDRESS; mBinder.discoverServices(clientIf, address, mAttributionSource); - verify(mService).discoverServices(clientIf, address, mAttributionSource); } @@ -191,7 +182,6 @@ public class GattServiceBinderTest { UUID uuid = UUID.randomUUID(); mBinder.discoverServiceByUuid(clientIf, address, new ParcelUuid(uuid), mAttributionSource); - verify(mService).discoverServiceByUuid(clientIf, address, uuid, mAttributionSource); } @@ -203,7 +193,6 @@ public class GattServiceBinderTest { int authReq = 3; mBinder.readCharacteristic(clientIf, address, handle, authReq, mAttributionSource); - verify(mService).readCharacteristic(clientIf, address, handle, authReq, mAttributionSource); } @@ -224,7 +213,6 @@ public class GattServiceBinderTest { endHandle, authReq, mAttributionSource); - verify(mService) .readUsingCharacteristicUuid( clientIf, @@ -247,7 +235,6 @@ public class GattServiceBinderTest { mBinder.writeCharacteristic( clientIf, address, handle, writeType, authReq, value, mAttributionSource); - verify(mService) .writeCharacteristic( clientIf, address, handle, writeType, authReq, value, mAttributionSource); @@ -261,7 +248,6 @@ public class GattServiceBinderTest { int authReq = 3; mBinder.readDescriptor(clientIf, address, handle, authReq, mAttributionSource); - verify(mService).readDescriptor(clientIf, address, handle, authReq, mAttributionSource); } @@ -274,7 +260,6 @@ public class GattServiceBinderTest { byte[] value = new byte[] {4, 5}; mBinder.writeDescriptor(clientIf, address, handle, authReq, value, mAttributionSource); - verify(mService) .writeDescriptor(clientIf, address, handle, authReq, value, mAttributionSource); } @@ -285,7 +270,6 @@ public class GattServiceBinderTest { String address = REMOTE_DEVICE_ADDRESS; mBinder.beginReliableWrite(clientIf, address, mAttributionSource); - verify(mService).beginReliableWrite(clientIf, address, mAttributionSource); } @@ -296,7 +280,6 @@ public class GattServiceBinderTest { boolean execute = true; mBinder.endReliableWrite(clientIf, address, execute, mAttributionSource); - verify(mService).endReliableWrite(clientIf, address, execute, mAttributionSource); } @@ -308,7 +291,6 @@ public class GattServiceBinderTest { boolean enable = true; mBinder.registerForNotification(clientIf, address, handle, enable, mAttributionSource); - verify(mService) .registerForNotification(clientIf, address, handle, enable, mAttributionSource); } @@ -319,7 +301,6 @@ public class GattServiceBinderTest { String address = REMOTE_DEVICE_ADDRESS; mBinder.readRemoteRssi(clientIf, address, mAttributionSource); - verify(mService).readRemoteRssi(clientIf, address, mAttributionSource); } @@ -330,7 +311,6 @@ public class GattServiceBinderTest { int mtu = 2; mBinder.configureMTU(clientIf, address, mtu, mAttributionSource); - verify(mService).configureMTU(clientIf, address, mtu, mAttributionSource); } @@ -342,7 +322,6 @@ public class GattServiceBinderTest { mBinder.connectionParameterUpdate( clientIf, address, connectionPriority, mAttributionSource); - verify(mService) .connectionParameterUpdate( clientIf, address, connectionPriority, mAttributionSource); @@ -369,7 +348,6 @@ public class GattServiceBinderTest { minConnectionEventLen, maxConnectionEventLen, mAttributionSource); - verify(mService) .leConnectionUpdate( clientIf, @@ -390,7 +368,6 @@ public class GattServiceBinderTest { boolean eattSupport = true; mBinder.registerServer(new ParcelUuid(uuid), callback, eattSupport, mAttributionSource); - verify(mService).registerServer(uuid, callback, eattSupport, mAttributionSource); } @@ -399,7 +376,6 @@ public class GattServiceBinderTest { int serverIf = 3; mBinder.unregisterServer(serverIf, mAttributionSource); - verify(mService).unregisterServer(serverIf, mAttributionSource); } @@ -413,7 +389,6 @@ public class GattServiceBinderTest { mBinder.serverConnect( serverIf, address, addressType, isDirect, transport, mAttributionSource); - verify(mService) .serverConnect( serverIf, address, addressType, isDirect, transport, mAttributionSource); @@ -425,7 +400,6 @@ public class GattServiceBinderTest { String address = REMOTE_DEVICE_ADDRESS; mBinder.serverDisconnect(serverIf, address, mAttributionSource); - verify(mService).serverDisconnect(serverIf, address, mAttributionSource); } @@ -439,7 +413,6 @@ public class GattServiceBinderTest { mBinder.serverSetPreferredPhy( serverIf, address, txPhy, rxPhy, phyOptions, mAttributionSource); - verify(mService) .serverSetPreferredPhy( serverIf, address, txPhy, rxPhy, phyOptions, mAttributionSource); @@ -451,7 +424,6 @@ public class GattServiceBinderTest { String address = REMOTE_DEVICE_ADDRESS; mBinder.serverReadPhy(serverIf, address, mAttributionSource); - verify(mService).serverReadPhy(serverIf, address, mAttributionSource); } @@ -461,7 +433,6 @@ public class GattServiceBinderTest { BluetoothGattService svc = mock(BluetoothGattService.class); mBinder.addService(serverIf, svc, mAttributionSource); - verify(mService).addService(serverIf, svc, mAttributionSource); } @@ -471,7 +442,6 @@ public class GattServiceBinderTest { int handle = 2; mBinder.removeService(serverIf, handle, mAttributionSource); - verify(mService).removeService(serverIf, handle, mAttributionSource); } @@ -480,7 +450,6 @@ public class GattServiceBinderTest { int serverIf = 1; mBinder.clearServices(serverIf, mAttributionSource); - verify(mService).clearServices(serverIf, mAttributionSource); } @@ -495,7 +464,6 @@ public class GattServiceBinderTest { mBinder.sendResponse( serverIf, address, requestId, status, offset, value, mAttributionSource); - verify(mService) .sendResponse( serverIf, address, requestId, status, offset, value, mAttributionSource); @@ -510,7 +478,6 @@ public class GattServiceBinderTest { byte[] value = new byte[] {5, 6}; mBinder.sendNotification(serverIf, address, handle, confirm, value, mAttributionSource); - verify(mService) .sendNotification(serverIf, address, handle, confirm, value, mAttributionSource); } @@ -518,12 +485,11 @@ public class GattServiceBinderTest { @Test public void disconnectAll() throws Exception { mBinder.disconnectAll(mAttributionSource); - verify(mService).disconnectAll(mAttributionSource); } @Test - public void cleanUp_doesNotCrash() { + public void cleanup_doesNotCrash() { mBinder.cleanup(); } } diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java index 76d6dd53ff..1e8a55b994 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java @@ -42,7 +42,6 @@ import android.content.res.Resources; import android.location.LocationManager; import android.os.Bundle; import android.os.Process; -import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.test.mock.MockContentProvider; import android.test.mock.MockContentResolver; @@ -54,7 +53,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.TestUtils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.CompanionManager; -import com.android.bluetooth.flags.Flags; import com.android.bluetooth.le_scan.PeriodicScanManager; import com.android.bluetooth.le_scan.ScanManager; import com.android.bluetooth.le_scan.ScanObjectsFactory; @@ -79,7 +77,6 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) public class GattServiceTest { @Rule public final MockitoRule mMockitoRule = new MockitoRule(); - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Mock private ContextMap<IBluetoothGattCallback> mClientMap; @Mock private ScanManager mScanManager; @@ -443,7 +440,6 @@ public class GattServiceTest { @Test public void registerClient_checkLimitPerApp() { - mSetFlagsRule.enableFlags(Flags.FLAG_GATT_CLIENT_DYNAMIC_ALLOCATION); doReturn(GattService.GATT_CLIENT_LIMIT_PER_APP).when(mClientMap).countByAppUid(anyInt()); UUID uuid = UUID.randomUUID(); IBluetoothGattCallback callback = mock(IBluetoothGattCallback.class); diff --git a/android/app/tests/unit/src/com/android/bluetooth/hap/HapClientBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/hap/HapClientServiceBinderTest.java index dd5ede57b2..3544578497 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/hap/HapClientBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/hap/HapClientServiceBinderTest.java @@ -44,9 +44,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; +/** Test cases for {@link HapClientServiceBinder} */ @MediumTest @RunWith(AndroidJUnit4.class) -public class HapClientBinderTest { +public class HapClientServiceBinderTest { @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private HapClientService mHapClientService; @@ -59,11 +60,11 @@ public class HapClientBinderTest { private final AttributionSource mAttributionSource = mAdapter.getAttributionSource(); private final BluetoothDevice mDevice = getTestDevice(0); - private HapClientBinder mBinder; + private HapClientServiceBinder mBinder; @Before public void setUp() throws Exception { - mBinder = new HapClientBinder(mHapClientService); + mBinder = new HapClientServiceBinder(mHapClientService); } @Test diff --git a/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceBinderTest.java new file mode 100644 index 0000000000..8dae3bf594 --- /dev/null +++ b/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceBinderTest.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.hearingaid; + +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; +import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import static com.android.bluetooth.TestUtils.MockitoRule; +import static com.android.bluetooth.TestUtils.getTestDevice; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothManager; +import android.content.AttributionSource; +import android.content.Context; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import java.util.ArrayList; +import java.util.List; + +/** Test cases for {@link HearingAidServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class HearingAidServiceBinderTest { + + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); + + @Mock private HearingAidService mService; + + private HearingAidServiceBinder mBinder; + private AttributionSource mAttributionSource; + private BluetoothDevice mTestDevice; + + @Before + public void setUp() throws Exception { + when(mService.isAvailable()).thenReturn(true); + mBinder = new HearingAidServiceBinder(mService); + Context context = InstrumentationRegistry.getTargetContext(); + mAttributionSource = + context.getSystemService(BluetoothManager.class) + .getAdapter() + .getAttributionSource(); + mTestDevice = getTestDevice(0); + } + + @Test + public void connect() { + mBinder.connect(mTestDevice, mAttributionSource); + verify(mService).connect(mTestDevice); + } + + @Test + public void disconnect() { + mBinder.disconnect(mTestDevice, mAttributionSource); + verify(mService).disconnect(mTestDevice); + } + + @Test + public void getConnectedDevices() { + List<BluetoothDevice> connectedDevices = new ArrayList<>(); + connectedDevices.add(mTestDevice); + when(mService.getConnectedDevices()).thenReturn(connectedDevices); + + mBinder.getConnectedDevices(mAttributionSource); + verify(mService).getConnectedDevices(); + } + + @Test + public void getDevicesMatchingConnectionStates() { + int[] states = new int[] {STATE_CONNECTED, STATE_DISCONNECTED}; + List<BluetoothDevice> devices = new ArrayList<>(); + devices.add(mTestDevice); + when(mService.getDevicesMatchingConnectionStates(states)).thenReturn(devices); + + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); + verify(mService).getDevicesMatchingConnectionStates(states); + } + + @Test + public void getConnectionState() { + when(mService.getConnectionState(mTestDevice)).thenReturn(STATE_CONNECTED); + + mBinder.getConnectionState(mTestDevice, mAttributionSource); + verify(mService).getConnectionState(mTestDevice); + } + + @Test + public void setActiveDevice() { + mBinder.setActiveDevice(mTestDevice, mAttributionSource); + verify(mService).setActiveDevice(mTestDevice); + } + + @Test + public void removeActiveDevice() { + mBinder.setActiveDevice(null, mAttributionSource); + verify(mService).removeActiveDevice(false); + } + + @Test + public void getActiveDevices() { + List<BluetoothDevice> activeDevices = new ArrayList<>(); + activeDevices.add(mTestDevice); + when(mService.getActiveDevices()).thenReturn(activeDevices); + + mBinder.getActiveDevices(mAttributionSource); + verify(mService).getActiveDevices(); + } + + @Test + public void setConnectionPolicy() { + mBinder.setConnectionPolicy(mTestDevice, CONNECTION_POLICY_ALLOWED, mAttributionSource); + verify(mService).setConnectionPolicy(mTestDevice, CONNECTION_POLICY_ALLOWED); + } + + @Test + public void getConnectionPolicy() { + when(mService.getConnectionPolicy(mTestDevice)).thenReturn(CONNECTION_POLICY_FORBIDDEN); + + mBinder.getConnectionPolicy(mTestDevice, mAttributionSource); + verify(mService).getConnectionPolicy(mTestDevice); + } + + @Test + public void setVolume() { + int volume = 50; + + mBinder.setVolume(volume, mAttributionSource); + verify(mService).setVolume(volume); + } + + @Test + public void getHiSyncId() { + long hiSyncId = 1234567890L; + when(mService.getHiSyncId(mTestDevice)).thenReturn(hiSyncId); + + mBinder.getHiSyncId(mTestDevice, mAttributionSource); + verify(mService).getHiSyncId(mTestDevice); + } + + @Test + public void getDeviceSide() { + int side = BluetoothHearingAid.SIDE_LEFT; + when(mService.getCapabilities(mTestDevice)).thenReturn(side); + + mBinder.getDeviceSide(mTestDevice, mAttributionSource); + verify(mService).getCapabilities(mTestDevice); + } + + @Test + public void getDeviceMode() { + int mode = BluetoothHearingAid.MODE_BINAURAL; + when(mService.getCapabilities(mTestDevice)).thenReturn(mode << 1); + + mBinder.getDeviceMode(mTestDevice, mAttributionSource); + verify(mService).getCapabilities(mTestDevice); + } + + @Test + public void getAdvertisementServiceData() { + BluetoothHearingAid.AdvertisementServiceData data = + new BluetoothHearingAid.AdvertisementServiceData(0, 0); + when(mService.getAdvertisementServiceData(mTestDevice)).thenReturn(data); + + mBinder.getAdvertisementServiceData(mTestDevice, mAttributionSource); + verify(mService).getAdvertisementServiceData(mTestDevice); + } + + @Test + public void cleanup_doesNotCrash() { + mBinder.cleanup(); + } +} diff --git a/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java index 757a6488be..a284d6a414 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java @@ -97,7 +97,7 @@ public class HearingAidServiceTest { private final BluetoothDevice mSingleDevice = getTestDevice(13); private HearingAidService mService; - private HearingAidService.BluetoothHearingAidBinder mBinder; + private HearingAidServiceBinder mBinder; private InOrder mInOrder; private TestLooper mLooper; @@ -124,7 +124,7 @@ public class HearingAidServiceTest { mService = new HearingAidService(mAdapterService, mLooper.getLooper(), mNativeInterface); mService.setAvailable(true); - mBinder = (HearingAidService.BluetoothHearingAidBinder) mService.initBinder(); + mBinder = (HearingAidServiceBinder) mService.initBinder(); } @After diff --git a/android/app/tests/unit/src/com/android/bluetooth/hearingaid/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/hearingaid/OWNERS deleted file mode 100644 index bbaa85ddbb..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/hearingaid/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_hearingaid diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java index 3edd1ff9ea..835f03aaa2 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java @@ -172,7 +172,9 @@ public class HeadsetServiceAndStateMachineTest { doReturn(true).when(mNativeInterface).disconnectAudio(any(BluetoothDevice.class)); doReturn(true).when(mNativeInterface).setActiveDevice(any(BluetoothDevice.class)); doReturn(true).when(mNativeInterface).sendBsir(any(BluetoothDevice.class), anyBoolean()); - doReturn(true).when(mNativeInterface).startVoiceRecognition(any(BluetoothDevice.class)); + doReturn(true) + .when(mNativeInterface) + .startVoiceRecognition(any(BluetoothDevice.class), anyBoolean()); doReturn(true).when(mNativeInterface).stopVoiceRecognition(any(BluetoothDevice.class)); doReturn(true) .when(mNativeInterface) @@ -1138,7 +1140,7 @@ public class HeadsetServiceAndStateMachineTest { mTestLooper.dispatchAll(); verify(mNativeInterface).setActiveDevice(deviceA); assertThat(mHeadsetService.getActiveDevice()).isEqualTo(deviceA); - verify(mNativeInterface).startVoiceRecognition(deviceA); + verify(mNativeInterface).startVoiceRecognition(deviceA, true); verify(mAudioManager).setA2dpSuspended(true); verify(mAudioManager).setLeAudioSuspended(true); verify(mNativeInterface).connectAudio(deviceA); @@ -1685,6 +1687,7 @@ public class HeadsetServiceAndStateMachineTest { // has not add verification AudioDeviceInfo because it is final, unless add a wrapper mHeadsetService.startVoiceRecognition(device); mTestLooper.dispatchAll(); + verify(mNativeInterface).startVoiceRecognition(device, false); verify(mAudioManager, times(0)).setA2dpSuspended(true); verify(mAudioManager, times(0)).setLeAudioSuspended(true); verify(mNativeInterface, times(0)).connectAudio(device); @@ -1695,7 +1698,7 @@ public class HeadsetServiceAndStateMachineTest { assertThat(device).isNotNull(); assertThat(mHeadsetService.startVoiceRecognition(device)).isTrue(); mTestLooper.dispatchAll(); - verify(mNativeInterface).startVoiceRecognition(device); + verify(mNativeInterface).startVoiceRecognition(device, true); verify(mAudioManager).setA2dpSuspended(true); verify(mAudioManager).setLeAudioSuspended(true); verify(mNativeInterface).connectAudio(device); @@ -1727,7 +1730,7 @@ public class HeadsetServiceAndStateMachineTest { mHeadsetService.startVoiceRecognition(device); mTestLooper.dispatchAll(); // has not add verification AudioDeviceInfo because it is final, unless add a wrapper - verify(mNativeInterface).startVoiceRecognition(device); + verify(mNativeInterface).startVoiceRecognition(device, true); verify(mAudioManager, times(0)).setA2dpSuspended(true); verify(mAudioManager, times(0)).setLeAudioSuspended(true); verify(mNativeInterface, times(0)).connectAudio(device); diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfp/BluetoothHeadsetBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceBinderTest.java index d125fbee4c..73f3610505 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/hfp/BluetoothHeadsetBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceBinderTest.java @@ -27,12 +27,20 @@ import static org.mockito.Mockito.verify; import android.bluetooth.BluetoothDevice; import android.content.AttributionSource; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; -public class BluetoothHeadsetBinderTest { +/** Test cases for {@link HeadsetServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class HeadsetServiceBinderTest { + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private HeadsetService mService; @@ -40,11 +48,11 @@ public class BluetoothHeadsetBinderTest { private final AttributionSource mAttributionSource = new AttributionSource.Builder(1).build(); private final BluetoothDevice mDevice = getTestDevice(39); - private HeadsetService.BluetoothHeadsetBinder mBinder; + private HeadsetServiceBinder mBinder; @Before public void setUp() throws Exception { - mBinder = new HeadsetService.BluetoothHeadsetBinder(mService); + mBinder = new HeadsetServiceBinder(mService); } @Test @@ -68,6 +76,7 @@ public class BluetoothHeadsetBinderTest { @Test public void getDevicesMatchingConnectionStates() { int[] states = new int[] {STATE_CONNECTED}; + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); verify(mService).getDevicesMatchingConnectionStates(states); } @@ -142,6 +151,7 @@ public class BluetoothHeadsetBinderTest { @Test public void setAudioRouteAllowed() { boolean allowed = true; + mBinder.setAudioRouteAllowed(allowed, mAttributionSource); verify(mService).setAudioRouteAllowed(allowed); } @@ -155,6 +165,7 @@ public class BluetoothHeadsetBinderTest { @Test public void setForceScoAudio() { boolean forced = true; + mBinder.setForceScoAudio(forced, mAttributionSource); verify(mService).setForceScoAudio(forced); } diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceBinderTest.java index b3171bc191..87f18055e5 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceBinderTest.java @@ -25,6 +25,7 @@ import static com.android.bluetooth.TestUtils.getTestDevice; import static org.mockito.Mockito.verify; import android.bluetooth.BluetoothDevice; +import android.content.AttributionSource; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -35,6 +36,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +/** Test cases for {@link HeadsetClientServiceBinder} */ @SmallTest @RunWith(AndroidJUnit4.class) public class HeadsetClientServiceBinderTest { @@ -42,32 +44,33 @@ public class HeadsetClientServiceBinderTest { @Mock private HeadsetClientService mService; + private final AttributionSource mAttributionSource = new AttributionSource.Builder(1).build(); private final BluetoothDevice mDevice = getTestDevice(54); - HeadsetClientService.BluetoothHeadsetClientBinder mBinder; + private HeadsetClientServiceBinder mBinder; @Before public void setUp() throws Exception { - mBinder = new HeadsetClientService.BluetoothHeadsetClientBinder(mService); + mBinder = new HeadsetClientServiceBinder(mService); } @Test public void connect_callsServiceMethod() { - mBinder.connect(mDevice, null); + mBinder.connect(mDevice, mAttributionSource); verify(mService).connect(mDevice); } @Test public void disconnect_callsServiceMethod() { - mBinder.disconnect(mDevice, null); + mBinder.disconnect(mDevice, mAttributionSource); verify(mService).disconnect(mDevice); } @Test public void getConnectedDevices_callsServiceMethod() { - mBinder.getConnectedDevices(null); + mBinder.getConnectedDevices(mAttributionSource); verify(mService).getConnectedDevices(); } @@ -75,14 +78,14 @@ public class HeadsetClientServiceBinderTest { @Test public void getDevicesMatchingConnectionStates_callsServiceMethod() { int[] states = new int[] {STATE_CONNECTED}; - mBinder.getDevicesMatchingConnectionStates(states, null); + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); verify(mService).getDevicesMatchingConnectionStates(states); } @Test public void getConnectionState_callsServiceMethod() { - mBinder.getConnectionState(mDevice, null); + mBinder.getConnectionState(mDevice, mAttributionSource); verify(mService).getConnectionState(mDevice); } @@ -90,35 +93,35 @@ public class HeadsetClientServiceBinderTest { @Test public void setConnectionPolicy_callsServiceMethod() { int connectionPolicy = CONNECTION_POLICY_ALLOWED; - mBinder.setConnectionPolicy(mDevice, connectionPolicy, null); + mBinder.setConnectionPolicy(mDevice, connectionPolicy, mAttributionSource); verify(mService).setConnectionPolicy(mDevice, connectionPolicy); } @Test public void getConnectionPolicy_callsServiceMethod() { - mBinder.getConnectionPolicy(mDevice, null); + mBinder.getConnectionPolicy(mDevice, mAttributionSource); verify(mService).getConnectionPolicy(mDevice); } @Test public void startVoiceRecognition_callsServiceMethod() { - mBinder.startVoiceRecognition(mDevice, null); + mBinder.startVoiceRecognition(mDevice, mAttributionSource); verify(mService).startVoiceRecognition(mDevice); } @Test public void stopVoiceRecognition_callsServiceMethod() { - mBinder.stopVoiceRecognition(mDevice, null); + mBinder.stopVoiceRecognition(mDevice, mAttributionSource); verify(mService).stopVoiceRecognition(mDevice); } @Test public void getAudioState_callsServiceMethod() { - mBinder.getAudioState(mDevice, null); + mBinder.getAudioState(mDevice, mAttributionSource); verify(mService).getAudioState(mDevice); } @@ -126,28 +129,28 @@ public class HeadsetClientServiceBinderTest { @Test public void setAudioRouteAllowed_callsServiceMethod() { boolean allowed = true; - mBinder.setAudioRouteAllowed(mDevice, allowed, null); + mBinder.setAudioRouteAllowed(mDevice, allowed, mAttributionSource); verify(mService).setAudioRouteAllowed(mDevice, allowed); } @Test public void getAudioRouteAllowed_callsServiceMethod() { - mBinder.getAudioRouteAllowed(mDevice, null); + mBinder.getAudioRouteAllowed(mDevice, mAttributionSource); verify(mService).getAudioRouteAllowed(mDevice); } @Test public void connectAudio_callsServiceMethod() { - mBinder.connectAudio(mDevice, null); + mBinder.connectAudio(mDevice, mAttributionSource); verify(mService).connectAudio(mDevice); } @Test public void disconnectAudio_callsServiceMethod() { - mBinder.disconnectAudio(mDevice, null); + mBinder.disconnectAudio(mDevice, mAttributionSource); verify(mService).disconnectAudio(mDevice); } @@ -155,35 +158,35 @@ public class HeadsetClientServiceBinderTest { @Test public void acceptCall_callsServiceMethod() { int flag = 2; - mBinder.acceptCall(mDevice, flag, null); + mBinder.acceptCall(mDevice, flag, mAttributionSource); verify(mService).acceptCall(mDevice, flag); } @Test public void rejectCall_callsServiceMethod() { - mBinder.rejectCall(mDevice, null); + mBinder.rejectCall(mDevice, mAttributionSource); verify(mService).rejectCall(mDevice); } @Test public void holdCall_callsServiceMethod() { - mBinder.holdCall(mDevice, null); + mBinder.holdCall(mDevice, mAttributionSource); verify(mService).holdCall(mDevice); } @Test public void terminateCall_callsServiceMethod() { - mBinder.terminateCall(mDevice, null, null); + mBinder.terminateCall(mDevice, null, mAttributionSource); verify(mService).terminateCall(mDevice, null); } @Test public void explicitCallTransfer_callsServiceMethod() { - mBinder.explicitCallTransfer(mDevice, null); + mBinder.explicitCallTransfer(mDevice, mAttributionSource); verify(mService).explicitCallTransfer(mDevice); } @@ -191,7 +194,7 @@ public class HeadsetClientServiceBinderTest { @Test public void enterPrivateMode_callsServiceMethod() { int index = 1; - mBinder.enterPrivateMode(mDevice, index, null); + mBinder.enterPrivateMode(mDevice, index, mAttributionSource); verify(mService).enterPrivateMode(mDevice, index); } @@ -199,7 +202,7 @@ public class HeadsetClientServiceBinderTest { @Test public void dial_callsServiceMethod() { String number = "12532523"; - mBinder.dial(mDevice, number, null); + mBinder.dial(mDevice, number, mAttributionSource); verify(mService).dial(mDevice, number); } @@ -207,21 +210,21 @@ public class HeadsetClientServiceBinderTest { @Test public void sendDTMF_callsServiceMethod() { byte code = 21; - mBinder.sendDTMF(mDevice, code, null); + mBinder.sendDTMF(mDevice, code, mAttributionSource); verify(mService).sendDTMF(mDevice, code); } @Test public void getLastVoiceTagNumber_callsServiceMethod() { - mBinder.getLastVoiceTagNumber(mDevice, null); + mBinder.getLastVoiceTagNumber(mDevice, mAttributionSource); verify(mService).getLastVoiceTagNumber(mDevice); } @Test public void getCurrentAgEvents_callsServiceMethod() { - mBinder.getCurrentAgEvents(mDevice, null); + mBinder.getCurrentAgEvents(mDevice, mAttributionSource); verify(mService).getCurrentAgEvents(mDevice); } @@ -231,14 +234,14 @@ public class HeadsetClientServiceBinderTest { int vendorId = 5; String cmd = "test_command"; - mBinder.sendVendorAtCommand(mDevice, vendorId, cmd, null); + mBinder.sendVendorAtCommand(mDevice, vendorId, cmd, mAttributionSource); verify(mService).sendVendorAtCommand(mDevice, vendorId, cmd); } @Test public void getCurrentAgFeatures_callsServiceMethod() { - mBinder.getCurrentAgFeatures(mDevice, null); + mBinder.getCurrentAgFeatures(mDevice, mAttributionSource); verify(mService).getCurrentAgFeaturesBundle(mDevice); } diff --git a/android/app/tests/unit/src/com/android/bluetooth/hid/BluetoothHidDeviceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceServiceBinderTest.java index 8a03fe7186..4369e85310 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/hid/BluetoothHidDeviceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceServiceBinderTest.java @@ -33,12 +33,20 @@ import android.bluetooth.BluetoothHidDeviceAppSdpSettings; import android.bluetooth.IBluetoothHidDeviceCallback; import android.content.AttributionSource; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; -public class BluetoothHidDeviceBinderTest { +/** Test cases for {@link HidDeviceServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class HidDeviceServiceBinderTest { + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private HidDeviceService mService; @@ -46,12 +54,12 @@ public class BluetoothHidDeviceBinderTest { private final AttributionSource mAttributionSource = new AttributionSource.Builder(1).build(); private final BluetoothDevice mDevice = getTestDevice(29); - private HidDeviceService.BluetoothHidDeviceBinder mBinder; + private HidDeviceServiceBinder mBinder; @Before public void setUp() throws Exception { when(mService.isAvailable()).thenReturn(true); - mBinder = new HidDeviceService.BluetoothHidDeviceBinder(mService); + mBinder = new HidDeviceServiceBinder(mService); } @Test diff --git a/android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceServiceTest.java index 5ddb36e4c6..a242f054a7 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceServiceTest.java @@ -76,7 +76,7 @@ import org.mockito.hamcrest.MockitoHamcrest; @MediumTest @RunWith(AndroidJUnit4.class) -public class HidDeviceTest { +public class HidDeviceServiceTest { @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private AdapterService mAdapterService; diff --git a/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceBinderTest.java index 02bee889e8..2c393118bb 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceBinderTest.java @@ -25,6 +25,7 @@ import static com.android.bluetooth.TestUtils.getTestDevice; import static org.mockito.Mockito.verify; import android.bluetooth.BluetoothDevice; +import android.content.AttributionSource; import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.filters.SmallTest; @@ -36,108 +37,103 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +/** Test cases for {@link HidHostServiceBinder}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class HidHostServiceBinderTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private HidHostService mService; + private final AttributionSource mAttributionSource = new AttributionSource.Builder(1).build(); private final BluetoothDevice mDevice = getTestDevice(50); - private HidHostService.BluetoothHidHostBinder mBinder; + private HidHostServiceBinder mBinder; @Before public void setUp() { - mBinder = new HidHostService.BluetoothHidHostBinder(mService); + mBinder = new HidHostServiceBinder(mService); } @Test public void connect_callsServiceMethod() { - mBinder.connect(mDevice, null); - + mBinder.connect(mDevice, mAttributionSource); verify(mService).connect(mDevice); } @Test public void disconnect_callsServiceMethod() { - mBinder.disconnect(mDevice, null); - + mBinder.disconnect(mDevice, mAttributionSource); verify(mService).disconnect(mDevice); } @Test public void getConnectedDevices_callsServiceMethod() { - mBinder.getConnectedDevices(null); - + mBinder.getConnectedDevices(mAttributionSource); verify(mService).getDevicesMatchingConnectionStates(new int[] {STATE_CONNECTED}); } @Test public void getDevicesMatchingConnectionStates_callsServiceMethod() { int[] states = new int[] {STATE_CONNECTED}; - mBinder.getDevicesMatchingConnectionStates(states, null); + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); verify(mService).getDevicesMatchingConnectionStates(states); } @Test public void getConnectionState_callsServiceMethod() { - mBinder.getConnectionState(mDevice, null); - + mBinder.getConnectionState(mDevice, mAttributionSource); verify(mService).getConnectionState(mDevice); } @Test public void setConnectionPolicy_callsServiceMethod() { int connectionPolicy = CONNECTION_POLICY_ALLOWED; - mBinder.setConnectionPolicy(mDevice, connectionPolicy, null); + mBinder.setConnectionPolicy(mDevice, connectionPolicy, mAttributionSource); verify(mService).setConnectionPolicy(mDevice, connectionPolicy); } @Test public void getConnectionPolicy_callsServiceMethod() { - mBinder.getConnectionPolicy(mDevice, null); - + mBinder.getConnectionPolicy(mDevice, mAttributionSource); verify(mService).getConnectionPolicy(mDevice); } @Test public void setPreferredTransport_callsServiceMethod() { int preferredTransport = BluetoothDevice.TRANSPORT_AUTO; - mBinder.setPreferredTransport(mDevice, preferredTransport, null); + mBinder.setPreferredTransport(mDevice, preferredTransport, mAttributionSource); verify(mService).setPreferredTransport(mDevice, preferredTransport); } @Test public void getPreferredTransport_callsServiceMethod() { - mBinder.getPreferredTransport(mDevice, null); - + mBinder.getPreferredTransport(mDevice, mAttributionSource); verify(mService).getPreferredTransport(mDevice); } @Test public void getProtocolMode_callsServiceMethod() { - mBinder.getProtocolMode(mDevice, null); - + mBinder.getProtocolMode(mDevice, mAttributionSource); verify(mService).getProtocolMode(mDevice); } @Test public void virtualUnplug_callsServiceMethod() { - mBinder.virtualUnplug(mDevice, null); - + mBinder.virtualUnplug(mDevice, mAttributionSource); verify(mService).virtualUnplug(mDevice); } @Test public void setProtocolMode_callsServiceMethod() { int protocolMode = 1; - mBinder.setProtocolMode(mDevice, protocolMode, null); + mBinder.setProtocolMode(mDevice, protocolMode, mAttributionSource); verify(mService).setProtocolMode(mDevice, protocolMode); } @@ -146,8 +142,8 @@ public class HidHostServiceBinderTest { byte reportType = 1; byte reportId = 2; int bufferSize = 16; - mBinder.getReport(mDevice, reportType, reportId, bufferSize, null); + mBinder.getReport(mDevice, reportType, reportId, bufferSize, mAttributionSource); verify(mService).getReport(mDevice, reportType, reportId, bufferSize); } @@ -155,31 +151,30 @@ public class HidHostServiceBinderTest { public void setReport_callsServiceMethod() { byte reportType = 1; String report = "test_report"; - mBinder.setReport(mDevice, reportType, report, null); + mBinder.setReport(mDevice, reportType, report, mAttributionSource); verify(mService).setReport(mDevice, reportType, report); } @Test public void sendData_callsServiceMethod() { String report = "test_report"; - mBinder.sendData(mDevice, report, null); + mBinder.sendData(mDevice, report, mAttributionSource); verify(mService).sendData(mDevice, report); } @Test public void setIdleTime_callsServiceMethod() { byte idleTime = 1; - mBinder.setIdleTime(mDevice, idleTime, null); + mBinder.setIdleTime(mDevice, idleTime, mAttributionSource); verify(mService).setIdleTime(mDevice, idleTime); } @Test public void getIdleTime_callsServiceMethod() { - mBinder.getIdleTime(mDevice, null); - + mBinder.getIdleTime(mDevice, mAttributionSource); verify(mService).getIdleTime(mDevice); } diff --git a/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java index a41f93d5d6..10f5f3257f 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.bluetooth.hid; import static android.bluetooth.BluetoothDevice.BOND_BONDED; @@ -53,6 +54,7 @@ import java.util.List; @MediumTest @RunWith(AndroidJUnit4.class) public class HidHostServiceTest { + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private AdapterService mAdapterService; diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceBinderTest.java index 15b3563df1..68677ffedb 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceBinderTest.java @@ -36,15 +36,23 @@ import android.content.AttributionSource; import android.os.ParcelUuid; import android.platform.test.flag.junit.SetFlagsRule; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import java.util.UUID; -public class LeAudioBinderTest { +/** Test cases for {@link LeAudioServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class LeAudioServiceBinderTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @@ -53,11 +61,11 @@ public class LeAudioBinderTest { private static final String TEST_BROADCAST_NAME = "TEST"; private static final int TEST_QUALITY = BluetoothLeBroadcastSubgroupSettings.QUALITY_STANDARD; - private LeAudioService.BluetoothLeAudioBinder mBinder; + private LeAudioServiceBinder mBinder; @Before public void setUp() { - mBinder = new LeAudioService.BluetoothLeAudioBinder(mService); + mBinder = new LeAudioServiceBinder(mService); } @Test diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java index f0f2037358..cf836ddc3c 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java @@ -76,12 +76,12 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.FlagsParameterization; import android.platform.test.flag.junit.SetFlagsRule; import android.sysprop.BluetoothProperties; import androidx.test.filters.MediumTest; import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.TestUtils; import com.android.bluetooth.bass_client.BassClientService; @@ -113,15 +113,20 @@ import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.hamcrest.MockitoHamcrest; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; @MediumTest -@RunWith(AndroidJUnit4.class) +@RunWith(ParameterizedAndroidJunit4.class) public class LeAudioServiceTest { - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule public final SetFlagsRule mSetFlagsRule; @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private AdapterService mAdapterService; @@ -201,6 +206,20 @@ public class LeAudioServiceTest { private InOrder mInOrder; + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return FlagsParameterization.progressionOf( + Flags.FLAG_LEAUDIO_BROADCAST_PRIMARY_GROUP_SELECTION, + Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX, + Flags.FLAG_LEAUDIO_UNICAST_NO_AVAILABLE_CONTEXTS, + Flags.FLAG_LEAUDIO_BROADCAST_API_MANAGE_PRIMARY_GROUP, + Flags.FLAG_DO_NOT_HARDCODE_TMAP_ROLE_MASK); + } + + public LeAudioServiceTest(FlagsParameterization flags) { + mSetFlagsRule = new SetFlagsRule(flags); + } + @Before public void setUp() throws Exception { mInOrder = inOrder(mAdapterService); @@ -211,11 +230,9 @@ public class LeAudioServiceTest { doReturn(mTargetContext.getContentResolver()).when(mAdapterService).getContentResolver(); doReturn(MAX_LE_AUDIO_CONNECTIONS).when(mAdapterService).getMaxConnectedAudioDevices(); - doReturn( - (long) (1 << BluetoothProfile.LE_AUDIO_BROADCAST) - | (1 << BluetoothProfile.LE_AUDIO)) - .when(mAdapterService) - .getSupportedProfilesBitMask(); + injectSupportedProfilesBitMask( + Set.of(BluetoothProfile.LE_AUDIO_BROADCAST, BluetoothProfile.LE_AUDIO)); + doReturn(new ParcelUuid[] {BluetoothUuid.LE_AUDIO}) .when(mAdapterService) .getRemoteUuids(any(BluetoothDevice.class)); @@ -280,6 +297,43 @@ public class LeAudioServiceTest { assertThat(LeAudioService.getLeAudioService()).isNull(); } + @Test + @EnableFlags(Flags.FLAG_DO_NOT_HARDCODE_TMAP_ROLE_MASK) + public void testTmapRoleMask() { + List<Set<Integer>> powerSet = + List.of( + Set.of(BluetoothProfile.LE_CALL_CONTROL), + Set.of(BluetoothProfile.MCP_SERVER), + Set.of(BluetoothProfile.LE_CALL_CONTROL, BluetoothProfile.MCP_SERVER), + Set.of(BluetoothProfile.LE_AUDIO_BROADCAST), + Set.of( + BluetoothProfile.LE_AUDIO_BROADCAST, + BluetoothProfile.LE_CALL_CONTROL), + Set.of(BluetoothProfile.LE_AUDIO_BROADCAST, BluetoothProfile.MCP_SERVER), + Set.of( + BluetoothProfile.LE_AUDIO_BROADCAST, + BluetoothProfile.LE_CALL_CONTROL, + BluetoothProfile.MCP_SERVER)); + + List<Integer> tmapMasks = + powerSet.stream() + .map( + set -> { + injectSupportedProfilesBitMask(set); + LeAudioService service = + new LeAudioService(mAdapterService, mNativeInterface); + return service.getTmapRoleMask(); + }) + .collect(Collectors.toList()); + + List<Integer> expectedMasks = + powerSet.stream() + .map(LeAudioServiceTest::constructTmapRoleMask) + .collect(Collectors.toList()); + + assertThat(tmapMasks).containsExactly(expectedMasks.toArray()).inOrder(); + } + /** Test getting LeAudio Service: getLeAudioService() */ @Test public void testGetLeAudioService() { @@ -1788,8 +1842,8 @@ public class LeAudioServiceTest { /** Test native interface group status message handling */ @Test + @EnableFlags(Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX) public void testMessageFromNativeGroupCodecConfigChangedNonActiveDevice() { - mSetFlagsRule.enableFlags(Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX); onGroupCodecConfChangedCallbackCalled = false; injectLocalCodecConfigCapaChanged(INPUT_CAPABILITIES_CONFIG, OUTPUT_CAPABILITIES_CONFIG); @@ -1874,8 +1928,8 @@ public class LeAudioServiceTest { /** Test native interface group status message handling */ @Test + @EnableFlags(Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX) public void testMessageFromNativeGroupCodecConfigChangedActiveDevice_DifferentConfiguration() { - mSetFlagsRule.enableFlags(Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX); onGroupCodecConfChangedCallbackCalled = false; injectLocalCodecConfigCapaChanged(INPUT_CAPABILITIES_CONFIG, OUTPUT_CAPABILITIES_CONFIG); @@ -3216,4 +3270,30 @@ public class LeAudioServiceTest { .sendBroadcastAsUser( MockitoHamcrest.argThat(AllOf.allOf(matchers)), any(), any(), any()); } + + private void injectSupportedProfilesBitMask(Set<Integer> profiles) { + long mask = 0; + for (int profile : profiles) { + mask |= (long) (1 << profile); + } + doReturn(mask).when(mAdapterService).getSupportedProfilesBitMask(); + } + + private static int constructTmapRoleMask(Set<Integer> profiles) { + int mask = 0; + for (int profile : profiles) { + switch (profile) { + case BluetoothProfile.LE_CALL_CONTROL: + mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG; + break; + case BluetoothProfile.MCP_SERVER: + mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS; + break; + case BluetoothProfile.LE_AUDIO_BROADCAST: + mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_BMS; + break; + } + } + return mask; + } } diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/le_audio/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.java deleted file mode 100644 index 61c7df48b8..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2025 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.bluetooth.le_scan; - -import static com.android.bluetooth.TestUtils.MockitoRule; -import static com.android.bluetooth.TestUtils.getTestDevice; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import android.app.PendingIntent; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothManager; -import android.bluetooth.le.IPeriodicAdvertisingCallback; -import android.bluetooth.le.IScannerCallback; -import android.bluetooth.le.ScanFilter; -import android.bluetooth.le.ScanResult; -import android.bluetooth.le.ScanSettings; -import android.content.AttributionSource; -import android.content.Intent; -import android.os.WorkSource; - -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; - -import java.util.ArrayList; -import java.util.List; - -/** Test cases for {@link ScanBinder}. */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class ScanBinderTest { - @Rule public final MockitoRule mMockitoRule = new MockitoRule(); - - @Mock private ScanController mScanController; - - private final AttributionSource mAttributionSource = - InstrumentationRegistry.getInstrumentation() - .getTargetContext() - .getSystemService(BluetoothManager.class) - .getAdapter() - .getAttributionSource(); - private final BluetoothDevice mDevice = getTestDevice(89); - private ScanBinder mBinder; - - @Before - public void setUp() { - mBinder = new ScanBinder(mScanController); - } - - @Test - public void registerScanner() { - IScannerCallback callback = mock(IScannerCallback.class); - WorkSource workSource = mock(WorkSource.class); - - mBinder.registerScanner(callback, workSource, mAttributionSource); - verify(mScanController).registerScanner(callback, workSource, mAttributionSource); - } - - @Test - public void unregisterScanner() { - int scannerId = 1; - - mBinder.unregisterScanner(scannerId, mAttributionSource); - verify(mScanController).unregisterScanner(scannerId, mAttributionSource); - } - - @Test - public void startScan() { - int scannerId = 1; - ScanSettings settings = new ScanSettings.Builder().build(); - List<ScanFilter> filters = new ArrayList<>(); - - mBinder.startScan(scannerId, settings, filters, mAttributionSource); - verify(mScanController).startScan(scannerId, settings, filters, mAttributionSource); - } - - @Test - public void startScanForIntent() { - PendingIntent intent = - PendingIntent.getBroadcast( - InstrumentationRegistry.getInstrumentation().getTargetContext(), - 0, - new Intent(), - PendingIntent.FLAG_IMMUTABLE); - ScanSettings settings = new ScanSettings.Builder().build(); - List<ScanFilter> filters = new ArrayList<>(); - - mBinder.startScanForIntent(intent, settings, filters, mAttributionSource); - verify(mScanController) - .registerPiAndStartScan(intent, settings, filters, mAttributionSource); - } - - @Test - public void stopScan_withScannerId() { - int scannerId = 1; - - mBinder.stopScan(scannerId, mAttributionSource); - verify(mScanController).stopScan(scannerId, mAttributionSource); - } - - @Test - public void stopScan_withIntent() { - PendingIntent intent = - PendingIntent.getBroadcast( - InstrumentationRegistry.getInstrumentation().getTargetContext(), - 0, - new Intent(), - PendingIntent.FLAG_IMMUTABLE); - - mBinder.stopScanForIntent(intent, mAttributionSource); - verify(mScanController).stopScan(intent, mAttributionSource); - } - - @Test - public void flushPendingBatchResults() { - int scannerId = 1; - - mBinder.flushPendingBatchResults(scannerId, mAttributionSource); - verify(mScanController).flushPendingBatchResults(scannerId, mAttributionSource); - } - - @Test - public void registerSync() { - ScanResult scanResult = new ScanResult(mDevice, null, 0, 0); - int skip = 1; - int timeout = 2; - IPeriodicAdvertisingCallback callback = mock(IPeriodicAdvertisingCallback.class); - - mBinder.registerSync(scanResult, skip, timeout, callback, mAttributionSource); - verify(mScanController) - .registerSync(scanResult, skip, timeout, callback, mAttributionSource); - } - - @Test - public void unregisterSync() { - IPeriodicAdvertisingCallback callback = mock(IPeriodicAdvertisingCallback.class); - - mBinder.unregisterSync(callback, mAttributionSource); - verify(mScanController).unregisterSync(callback, mAttributionSource); - } - - @Test - public void transferSync() { - int serviceData = 1; - int syncHandle = 2; - - mBinder.transferSync(mDevice, serviceData, syncHandle, mAttributionSource); - verify(mScanController).transferSync(mDevice, serviceData, syncHandle, mAttributionSource); - } - - @Test - public void transferSetInfo() { - int serviceData = 1; - int advHandle = 2; - IPeriodicAdvertisingCallback callback = mock(IPeriodicAdvertisingCallback.class); - - mBinder.transferSetInfo(mDevice, serviceData, advHandle, callback, mAttributionSource); - verify(mScanController) - .transferSetInfo(mDevice, serviceData, advHandle, callback, mAttributionSource); - } - - @Test - public void numHwTrackFiltersAvailable() { - mBinder.numHwTrackFiltersAvailable(mAttributionSource); - verify(mScanController).numHwTrackFiltersAvailable(mAttributionSource); - } - - @Test - public void cleanup_doesNotCrash() { - mBinder.cleanup(); - } -} diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.kt b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.kt new file mode 100644 index 0000000000..3424c48a54 --- /dev/null +++ b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.kt @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.le_scan + +import android.app.PendingIntent +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothManager +import android.bluetooth.le.IPeriodicAdvertisingCallback +import android.bluetooth.le.IScannerCallback +import android.bluetooth.le.ScanFilter +import android.bluetooth.le.ScanResult +import android.bluetooth.le.ScanSettings +import android.content.Intent +import android.os.WorkSource +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import com.android.bluetooth.TestUtils.MockitoRule +import com.android.bluetooth.TestUtils.getTestDevice +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify + +/** Test cases for [ScanBinder] */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class ScanBinderTest { + + @get:Rule val mockitoRule = MockitoRule() + + @Mock private lateinit var scanController: ScanController + + private val attributionSource = + InstrumentationRegistry.getInstrumentation() + .targetContext + .getSystemService(BluetoothManager::class.java) + .adapter + .attributionSource + private val device: BluetoothDevice = getTestDevice(89) + private lateinit var binder: ScanBinder + + @Before + fun setUp() { + binder = ScanBinder(scanController) + } + + @Test + fun registerScanner() { + val callback = mock(IScannerCallback::class.java) + val workSource = mock(WorkSource::class.java) + + binder.registerScanner(callback, workSource, attributionSource) + verify(scanController).registerScanner(callback, workSource, attributionSource) + } + + @Test + fun unregisterScanner() { + val scannerId = 1 + + binder.unregisterScanner(scannerId, attributionSource) + verify(scanController).unregisterScanner(scannerId, attributionSource) + } + + @Test + fun startScan() { + val scannerId = 1 + val settings = ScanSettings.Builder().build() + val filters = listOf<ScanFilter>() + + binder.startScan(scannerId, settings, filters, attributionSource) + verify(scanController).startScan(scannerId, settings, filters, attributionSource) + } + + @Test + fun startScanForIntent() { + val intent = + PendingIntent.getBroadcast( + InstrumentationRegistry.getInstrumentation().targetContext, + 0, + Intent(), + PendingIntent.FLAG_IMMUTABLE, + ) + val settings = ScanSettings.Builder().build() + val filters = listOf<ScanFilter>() + + binder.startScanForIntent(intent, settings, filters, attributionSource) + verify(scanController).registerPiAndStartScan(intent, settings, filters, attributionSource) + } + + @Test + fun stopScan_withScannerId() { + val scannerId = 1 + + binder.stopScan(scannerId, attributionSource) + verify(scanController).stopScan(scannerId, attributionSource) + } + + @Test + fun stopScan_withIntent() { + val intent = + PendingIntent.getBroadcast( + InstrumentationRegistry.getInstrumentation().targetContext, + 0, + Intent(), + PendingIntent.FLAG_IMMUTABLE, + ) + + binder.stopScanForIntent(intent, attributionSource) + verify(scanController).stopScan(intent, attributionSource) + } + + @Test + fun flushPendingBatchResults() { + val scannerId = 1 + + binder.flushPendingBatchResults(scannerId, attributionSource) + verify(scanController).flushPendingBatchResults(scannerId, attributionSource) + } + + @Test + fun registerSync() { + val scanResult = mock(ScanResult::class.java) + val skip = 1 + val timeout = 2 + val callback = mock(IPeriodicAdvertisingCallback::class.java) + + binder.registerSync(scanResult, skip, timeout, callback, attributionSource) + verify(scanController).registerSync(scanResult, skip, timeout, callback, attributionSource) + } + + @Test + fun unregisterSync() { + val callback = mock(IPeriodicAdvertisingCallback::class.java) + + binder.unregisterSync(callback, attributionSource) + verify(scanController).unregisterSync(callback, attributionSource) + } + + @Test + fun transferSync() { + val serviceData = 1 + val syncHandle = 2 + + binder.transferSync(device, serviceData, syncHandle, attributionSource) + verify(scanController).transferSync(device, serviceData, syncHandle, attributionSource) + } + + @Test + fun transferSetInfo() { + val serviceData = 1 + val advHandle = 2 + val callback = mock(IPeriodicAdvertisingCallback::class.java) + + binder.transferSetInfo(device, serviceData, advHandle, callback, attributionSource) + verify(scanController) + .transferSetInfo(device, serviceData, advHandle, callback, attributionSource) + } + + @Test + fun numHwTrackFiltersAvailable() { + binder.numHwTrackFiltersAvailable(attributionSource) + verify(scanController).numHwTrackFiltersAvailable(attributionSource) + } + + @Test + fun cleanup_doesNotCrash() { + binder.cleanup() + } +} diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanManagerTest.java index 22d8fed0ac..54a3679ee6 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanManagerTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanManagerTest.java @@ -1227,7 +1227,6 @@ public class ScanManagerTest { } @Test - @EnableFlags(Flags.FLAG_BLE_SCAN_ADV_METRICS_REDESIGN) public void testMetricsAppScanScreenOn() { // Set filtered scan flag final boolean isFiltered = true; @@ -1292,7 +1291,8 @@ public class ScanManagerTest { 0, true, false, - IMPORTANCE_FOREGROUND_SERVICE); + IMPORTANCE_FOREGROUND_SERVICE, + ""); advanceTime(scanTestDuration); // Record scan stop @@ -1317,12 +1317,12 @@ public class ScanManagerTest { eq(0), eq(true), eq(false), - eq(IMPORTANCE_FOREGROUND_SERVICE)); + eq(IMPORTANCE_FOREGROUND_SERVICE), + eq("")); } } @Test - @EnableFlags(Flags.FLAG_BLE_SCAN_ADV_METRICS_REDESIGN) public void testMetricsRadioScanScreenOnOffMultiScan() { // Set filtered scan flag final boolean isFiltered = true; @@ -1390,7 +1390,8 @@ public class ScanManagerTest { eq((long) ScanManager.SCAN_MODE_LOW_POWER_WINDOW_MS), eq(true), eq(scanTestDuration), - eq(IMPORTANCE_FOREGROUND_SERVICE)); + eq(IMPORTANCE_FOREGROUND_SERVICE), + eq("")); advanceTime(scanTestDuration); // Create workSource for the third app @@ -1430,7 +1431,8 @@ public class ScanManagerTest { eq((long) ScanManager.SCAN_MODE_BALANCED_WINDOW_MS), eq(true), eq(scanTestDuration), - eq(IMPORTANCE_FOREGROUND_SERVICE)); + eq(IMPORTANCE_FOREGROUND_SERVICE), + eq("")); advanceTime(scanTestDuration); // Create workSource for the fourth app @@ -1467,7 +1469,8 @@ public class ScanManagerTest { anyLong(), anyBoolean(), anyLong(), - anyInt()); + anyInt(), + eq("")); advanceTime(scanTestDuration); // Set as background app @@ -1492,7 +1495,8 @@ public class ScanManagerTest { eq((long) ScanManager.SCAN_MODE_LOW_LATENCY_WINDOW_MS), eq(true), eq(scanTestDuration * 2), - eq(IMPORTANCE_FOREGROUND_SERVICE)); + eq(IMPORTANCE_FOREGROUND_SERVICE), + eq("")); advanceTime(scanTestDuration); // Get the most aggressive scan client when screen is off @@ -1521,7 +1525,8 @@ public class ScanManagerTest { eq((long) SCAN_MODE_SCREEN_OFF_LOW_POWER_WINDOW_MS), eq(false), eq(scanTestDuration), - eq(IMPORTANCE_FOREGROUND_SERVICE + 1)); + eq(IMPORTANCE_FOREGROUND_SERVICE + 1), + eq("")); advanceTime(scanTestDuration); // Stop scan for the fourth app @@ -1538,7 +1543,8 @@ public class ScanManagerTest { anyLong(), anyBoolean(), anyLong(), - anyInt()); + anyInt(), + eq("")); advanceTime(scanTestDuration); // Stop scan for the third app @@ -1558,7 +1564,8 @@ public class ScanManagerTest { eq((long) ScanManager.SCAN_MODE_LOW_LATENCY_WINDOW_MS), eq(true), eq(scanTestDuration * 2), - eq(IMPORTANCE_FOREGROUND_SERVICE)); + eq(IMPORTANCE_FOREGROUND_SERVICE), + eq("")); advanceTime(scanTestDuration); // Stop scan for the second app @@ -1578,7 +1585,8 @@ public class ScanManagerTest { eq((long) ScanManager.SCAN_MODE_BALANCED_WINDOW_MS), eq(true), eq(scanTestDuration), - eq(IMPORTANCE_FOREGROUND_SERVICE)); + eq(IMPORTANCE_FOREGROUND_SERVICE), + eq("")); advanceTime(scanTestDuration); // Stop scan for the first app @@ -1598,7 +1606,8 @@ public class ScanManagerTest { eq((long) ScanManager.SCAN_MODE_LOW_POWER_WINDOW_MS), eq(true), eq(scanTestDuration), - eq(IMPORTANCE_FOREGROUND_SERVICE)); + eq(IMPORTANCE_FOREGROUND_SERVICE), + eq("")); } @Test diff --git a/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapServiceBinderTest.java index fa0c3d3f35..0ebb4e7bd2 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/map/BluetoothMapServiceBinderTest.java @@ -25,6 +25,7 @@ import static com.android.bluetooth.TestUtils.getTestDevice; import static org.mockito.Mockito.verify; import android.bluetooth.BluetoothDevice; +import android.content.AttributionSource; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -35,88 +36,85 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +/** Test cases for {@link BluetoothMapServiceBinder} */ @SmallTest @RunWith(AndroidJUnit4.class) public class BluetoothMapServiceBinderTest { + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private BluetoothMapService mService; + private final AttributionSource mAttributionSource = new AttributionSource.Builder(1).build(); private final BluetoothDevice mDevice = getTestDevice(98); - private BluetoothMapService.BluetoothMapBinder mBinder; + private BluetoothMapServiceBinder mBinder; @Before public void setUp() throws Exception { - mBinder = new BluetoothMapService.BluetoothMapBinder(mService); + mBinder = new BluetoothMapServiceBinder(mService); } @Test public void disconnect_callsServiceMethod() { - mBinder.disconnect(mDevice, null); - + mBinder.disconnect(mDevice, mAttributionSource); verify(mService).disconnect(mDevice); } @Test public void getConnectedDevices_callsServiceMethod() { - mBinder.getConnectedDevices(null); - + mBinder.getConnectedDevices(mAttributionSource); verify(mService).getConnectedDevices(); } @Test public void getDevicesMatchingConnectionStates_callsServiceMethod() { int[] states = new int[] {STATE_CONNECTED}; - mBinder.getDevicesMatchingConnectionStates(states, null); + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); verify(mService).getDevicesMatchingConnectionStates(states); } @Test public void getConnectionState_callsServiceMethod() { - mBinder.getConnectionState(mDevice, null); - + mBinder.getConnectionState(mDevice, mAttributionSource); verify(mService).getConnectionState(mDevice); } @Test public void setConnectionPolicy_callsServiceMethod() { int connectionPolicy = CONNECTION_POLICY_ALLOWED; - mBinder.setConnectionPolicy(mDevice, connectionPolicy, null); + mBinder.setConnectionPolicy(mDevice, connectionPolicy, mAttributionSource); verify(mService).setConnectionPolicy(mDevice, connectionPolicy); } @Test public void getConnectionPolicy_callsServiceMethod() { - mBinder.getConnectionPolicy(mDevice, null); - + mBinder.getConnectionPolicy(mDevice, mAttributionSource); verify(mService).getConnectionPolicy(mDevice); } @Test public void getState_callsServiceMethod() { - mBinder.getState(null); - + mBinder.getState(mAttributionSource); verify(mService).getState(); } @Test public void isConnected_callsServiceStaticMethod() { - mBinder.isConnected(mDevice, null); - + mBinder.isConnected(mDevice, mAttributionSource); verify(mService).getConnectionState(mDevice); } @Test public void getClient_callsServiceStaticMethod() { - mBinder.getClient(null); + mBinder.getClient(mAttributionSource); verify(mService).getRemoteDevice(); } @Test - public void cleanUp_doesNotCrash() { + public void cleanup_doesNotCrash() { mBinder.cleanup(); } } diff --git a/android/app/tests/unit/src/com/android/bluetooth/map/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/map/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/map/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/mapapi/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/mapapi/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/mapapi/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientServiceBinderTest.java index 0830f8b9f9..4e6910718f 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientServiceBinderTest.java @@ -24,6 +24,7 @@ import static com.android.bluetooth.TestUtils.getTestDevice; import static org.mockito.Mockito.verify; import android.bluetooth.BluetoothDevice; +import android.content.AttributionSource; import android.net.Uri; import androidx.test.filters.MediumTest; @@ -35,70 +36,68 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +/** Test cases for {@link MapClientServiceBinder} */ @MediumTest @RunWith(AndroidJUnit4.class) public class MapClientServiceBinderTest { + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private MapClientService mService; + private final AttributionSource mAttributionSource = new AttributionSource.Builder(1).build(); private final BluetoothDevice mDevice = getTestDevice(65); - MapClientService.Binder mBinder; + private MapClientServiceBinder mBinder; @Before public void setUp() { - mBinder = new MapClientService.Binder(mService); + mBinder = new MapClientServiceBinder(mService); } @Test public void connect_callsServiceMethod() { - mBinder.connect(mDevice, null); - + mBinder.connect(mDevice, mAttributionSource); verify(mService).connect(mDevice); } @Test public void disconnect_callsServiceMethod() { - mBinder.disconnect(mDevice, null); - + mBinder.disconnect(mDevice, mAttributionSource); verify(mService).disconnect(mDevice); } @Test public void getConnectedDevices_callsServiceMethod() { - mBinder.getConnectedDevices(null); - + mBinder.getConnectedDevices(mAttributionSource); verify(mService).getConnectedDevices(); } @Test public void getDevicesMatchingConnectionStates_callsServiceMethod() { int[] states = new int[] {STATE_CONNECTED}; - mBinder.getDevicesMatchingConnectionStates(states, null); + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); verify(mService).getDevicesMatchingConnectionStates(states); } @Test public void getConnectionState_callsServiceMethod() { - mBinder.getConnectionState(mDevice, null); - + mBinder.getConnectionState(mDevice, mAttributionSource); verify(mService).getConnectionState(mDevice); } @Test public void setConnectionPolicy_callsServiceMethod() { int connectionPolicy = CONNECTION_POLICY_ALLOWED; - mBinder.setConnectionPolicy(mDevice, connectionPolicy, null); + mBinder.setConnectionPolicy(mDevice, connectionPolicy, mAttributionSource); verify(mService).setConnectionPolicy(mDevice, connectionPolicy); } @Test public void getConnectionPolicy_callsServiceMethod() { - mBinder.getConnectionPolicy(mDevice, null); - + mBinder.getConnectionPolicy(mDevice, mAttributionSource); verify(mService).getConnectionPolicy(mDevice); } @@ -106,13 +105,13 @@ public class MapClientServiceBinderTest { public void sendMessage_callsServiceMethod() { Uri[] contacts = new Uri[] {}; String message = "test_message"; - mBinder.sendMessage(mDevice, contacts, message, null, null, null); + mBinder.sendMessage(mDevice, contacts, message, null, null, mAttributionSource); verify(mService).sendMessage(mDevice, contacts, message, null, null); } @Test - public void cleanUp_doesNotCrash() { + public void cleanup_doesNotCrash() { mBinder.cleanup(); } } diff --git a/android/app/tests/unit/src/com/android/bluetooth/mapclient/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/mapclient/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/mapclient/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/mcp/McpServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/mcp/McpServiceBinderTest.java new file mode 100644 index 0000000000..dc21e810b8 --- /dev/null +++ b/android/app/tests/unit/src/com/android/bluetooth/mcp/McpServiceBinderTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.mcp; + +import static com.android.bluetooth.TestUtils.MockitoRule; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothDevice; +import android.content.AttributionSource; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +/** Test cases for {@link McpServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class McpServiceBinderTest { + + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); + + @Mock private McpService mService; + + private AttributionSource mAttributionSource; + private McpServiceBinder mBinder; + + @Before + public void setUp() throws Exception { + when(mService.isAvailable()).thenReturn(true); + mBinder = new McpServiceBinder(mService); + mAttributionSource = new AttributionSource.Builder(1).build(); + } + + @Test + public void setDeviceAuthorized() { + BluetoothDevice device = mock(BluetoothDevice.class); + boolean isAuthorized = true; + + mBinder.setDeviceAuthorized(device, isAuthorized, mAttributionSource); + verify(mService).setDeviceAuthorized(device, isAuthorized); + } + + @Test + public void cleanup_doesNotCrash() { + mBinder.cleanup(); + } +} diff --git a/android/app/tests/unit/src/com/android/bluetooth/mcp/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/mcp/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/mcp/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/app/tests/unit/src/com/android/bluetooth/obex/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/obex/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/obex/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppTransferTest.java b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppTransferTest.java index f6c393909c..3ab02065e3 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppTransferTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppTransferTest.java @@ -390,7 +390,6 @@ public class BluetoothOppTransferTest { @Test public void oppConnectionReceiver_onReceiveWithActionSdpRecord_withoutSdpRecord() { - mSetFlagRule.enableFlags(Flags.FLAG_IDENTITY_ADDRESS_NULL_IF_NOT_KNOWN); BluetoothDevice device = InstrumentationRegistry.getInstrumentation() .getTargetContext() diff --git a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppUtilityTest.java b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppUtilityTest.java index 705c91d518..cadff94862 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppUtilityTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppUtilityTest.java @@ -44,6 +44,7 @@ import android.content.pm.ResolveInfo; import android.database.Cursor; import android.net.Uri; import android.os.ParcelFileDescriptor; +import android.provider.Settings; import androidx.test.platform.app.InstrumentationRegistry; @@ -432,4 +433,22 @@ public class BluetoothOppUtilityTest { assertWithMessage("Exception should not happen. " + e).fail(); } } + + @Test + public void grantPermissionToNearbyComponent() { + Uri originalUri = Uri.parse("content://test.provider/1"); + Settings.Secure.putString( + mContext.getContentResolver(), + "nearby_sharing_component", + "com.example/.BComponent"); + Context spiedContext = spy(new ContextWrapper(mContext)); + + BluetoothOppUtility.grantPermissionToNearbyComponent(spiedContext, List.of(originalUri)); + + verify(spiedContext) + .grantUriPermission( + eq("com.example"), + eq(originalUri), + eq(Intent.FLAG_GRANT_READ_URI_PERMISSION)); + } } diff --git a/android/app/tests/unit/src/com/android/bluetooth/opp/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/opp/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/opp/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/pan/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/pan/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/pan/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/pan/PanServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/pan/PanServiceBinderTest.java index d798666437..272ada98d7 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/pan/PanServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/pan/PanServiceBinderTest.java @@ -25,6 +25,7 @@ import static com.android.bluetooth.TestUtils.getTestDevice; import static org.mockito.Mockito.verify; import android.bluetooth.BluetoothDevice; +import android.content.AttributionSource; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -35,75 +36,73 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +/** Test cases for {@link PanServiceBinder} */ @SmallTest @RunWith(AndroidJUnit4.class) public class PanServiceBinderTest { + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private PanService mService; + private final AttributionSource mAttributionSource = new AttributionSource.Builder(1).build(); private final BluetoothDevice mDevice = getTestDevice(64); - PanService.BluetoothPanBinder mBinder; + private PanServiceBinder mBinder; @Before public void setUp() throws Exception { - mBinder = new PanService.BluetoothPanBinder(mService); + mBinder = new PanServiceBinder(mService); } @Test public void connect_callsServiceMethod() { - mBinder.connect(mDevice, null); - + mBinder.connect(mDevice, mAttributionSource); verify(mService).connect(mDevice); } @Test public void disconnect_callsServiceMethod() { - mBinder.disconnect(mDevice, null); - + mBinder.disconnect(mDevice, mAttributionSource); verify(mService).disconnect(mDevice); } @Test public void getConnectedDevices_callsServiceMethod() { - mBinder.getConnectedDevices(null); - + mBinder.getConnectedDevices(mAttributionSource); verify(mService).getConnectedDevices(); } @Test public void getDevicesMatchingConnectionStates_callsServiceMethod() { int[] states = new int[] {STATE_CONNECTED}; - mBinder.getDevicesMatchingConnectionStates(states, null); + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); verify(mService).getDevicesMatchingConnectionStates(states); } @Test public void getConnectionState_callsServiceMethod() { - mBinder.getConnectionState(mDevice, null); - + mBinder.getConnectionState(mDevice, mAttributionSource); verify(mService).getConnectionState(mDevice); } @Test public void setConnectionPolicy_callsServiceMethod() { int connectionPolicy = CONNECTION_POLICY_ALLOWED; - mBinder.setConnectionPolicy(mDevice, connectionPolicy, null); + mBinder.setConnectionPolicy(mDevice, connectionPolicy, mAttributionSource); verify(mService).setConnectionPolicy(mDevice, connectionPolicy); } @Test public void isTetheringOn_callsServiceMethod() { - mBinder.isTetheringOn(null); - + mBinder.isTetheringOn(mAttributionSource); verify(mService).isTetheringOn(); } @Test - public void cleanUp_doesNotCrash() { + public void cleanup_doesNotCrash() { mBinder.cleanup(); } } diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapServiceBinderTest.java index 95b2bb25ef..5c713d62b5 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapServiceBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapServiceBinderTest.java @@ -25,6 +25,7 @@ import static com.android.bluetooth.TestUtils.getTestDevice; import static org.mockito.Mockito.verify; import android.bluetooth.BluetoothDevice; +import android.content.AttributionSource; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; @@ -35,32 +36,35 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +/** Test cases for {@link BluetoothPbapServiceBinder} */ @MediumTest @RunWith(AndroidJUnit4.class) public class BluetoothPbapServiceBinderTest { + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private BluetoothPbapService mService; + private final AttributionSource mAttributionSource = new AttributionSource.Builder(1).build(); private final BluetoothDevice mDevice = getTestDevice(60); - BluetoothPbapService.PbapBinder mBinder; + private BluetoothPbapServiceBinder mBinder; @Before public void setUp() { - mBinder = new BluetoothPbapService.PbapBinder(mService); + mBinder = new BluetoothPbapServiceBinder(mService); } @Test public void disconnect_callsServiceMethod() { - mBinder.disconnect(mDevice, null); + mBinder.disconnect(mDevice, mAttributionSource); verify(mService).disconnect(mDevice); } @Test public void getConnectedDevices_callsServiceMethod() { - mBinder.getConnectedDevices(null); + mBinder.getConnectedDevices(mAttributionSource); verify(mService).getConnectedDevices(); } @@ -68,14 +72,14 @@ public class BluetoothPbapServiceBinderTest { @Test public void getDevicesMatchingConnectionStates_callsServiceMethod() { int[] states = new int[] {STATE_CONNECTED}; - mBinder.getDevicesMatchingConnectionStates(states, null); + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); verify(mService).getDevicesMatchingConnectionStates(states); } @Test public void getConnectionState_callsServiceMethod() { - mBinder.getConnectionState(mDevice, null); + mBinder.getConnectionState(mDevice, mAttributionSource); verify(mService).getConnectionState(mDevice); } @@ -83,7 +87,7 @@ public class BluetoothPbapServiceBinderTest { @Test public void setConnectionPolicy_callsServiceMethod() { int connectionPolicy = CONNECTION_POLICY_ALLOWED; - mBinder.setConnectionPolicy(mDevice, connectionPolicy, null); + mBinder.setConnectionPolicy(mDevice, connectionPolicy, mAttributionSource); verify(mService).setConnectionPolicy(mDevice, connectionPolicy); } diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbap/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/pbap/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/pbap/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientObexTransportTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientObexTransportTest.java index dfcc542467..b594ac70b4 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientObexTransportTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientObexTransportTest.java @@ -183,7 +183,6 @@ public class PbapClientObexTransportTest { public void testGetRemoteAddress_transportRfcomm_returnsDeviceIdentityAddress() { doReturn(BluetoothSocket.TYPE_RFCOMM).when(mMockSocket).getConnectionType(); PbapClientObexTransport transport = new PbapClientObexTransport(mMockSocket); - // See "Flags.identityAddressNullIfNotKnown():" // Identity address won't be "known" by the stack for a test device, so it'll return null. // assertThat(transport.getRemoteAddress()).isNull(); assertThat(transport.getRemoteAddress()).isEqualTo(mTestDevice.getAddress()); diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceBinderTest.java index aff8f250a7..94b51136dd 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientBinderTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceBinderTest.java @@ -47,29 +47,30 @@ import org.mockito.Mock; import java.util.List; +/** Test cases for {@link PbapClientServiceBinder} */ @MediumTest @RunWith(AndroidJUnit4.class) -public class PbapClientBinderTest { +public class PbapClientServiceBinderTest { @Rule public final MockitoRule mMockitoRule = new MockitoRule(); @Mock private PbapClientService mMockService; private BluetoothDevice mTestDevice; private AttributionSource mAttributionSource; - private PbapClientBinder mPbapClientBinder; + private PbapClientServiceBinder mPbapClientServiceBinder; @Before public void setUp() throws Exception { mTestDevice = getTestDevice(1); mAttributionSource = new AttributionSource.Builder(1).build(); - mPbapClientBinder = new PbapClientBinder(mMockService); + mPbapClientServiceBinder = new PbapClientServiceBinder(mMockService); } @After public void tearDown() throws Exception { - if (mPbapClientBinder != null) { - mPbapClientBinder.cleanup(); - mPbapClientBinder = null; + if (mPbapClientServiceBinder != null) { + mPbapClientServiceBinder.cleanup(); + mPbapClientServiceBinder = null; } } @@ -79,45 +80,46 @@ public class PbapClientBinderTest { @Test public void testConnect() { - mPbapClientBinder.connect(mTestDevice, mAttributionSource); + mPbapClientServiceBinder.connect(mTestDevice, mAttributionSource); verify(mMockService).connect(eq(mTestDevice)); } @Test public void testDisconnect() { - mPbapClientBinder.disconnect(mTestDevice, mAttributionSource); + mPbapClientServiceBinder.disconnect(mTestDevice, mAttributionSource); verify(mMockService).disconnect(eq(mTestDevice)); } @Test public void testGetConnectedDevices() { - mPbapClientBinder.getConnectedDevices(mAttributionSource); + mPbapClientServiceBinder.getConnectedDevices(mAttributionSource); verify(mMockService).getConnectedDevices(); } @Test public void testGetDevicesMatchingConnectionStates() { int[] states = new int[] {STATE_CONNECTED}; - mPbapClientBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); + mPbapClientServiceBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); verify(mMockService).getDevicesMatchingConnectionStates(eq(states)); } @Test public void testGetConnectionState() { - mPbapClientBinder.getConnectionState(mTestDevice, mAttributionSource); + mPbapClientServiceBinder.getConnectionState(mTestDevice, mAttributionSource); verify(mMockService).getConnectionState(eq(mTestDevice)); } @Test public void testSetConnectionPolicy() { int connectionPolicy = CONNECTION_POLICY_ALLOWED; - mPbapClientBinder.setConnectionPolicy(mTestDevice, connectionPolicy, mAttributionSource); + mPbapClientServiceBinder.setConnectionPolicy( + mTestDevice, connectionPolicy, mAttributionSource); verify(mMockService).setConnectionPolicy(eq(mTestDevice), eq(connectionPolicy)); } @Test public void testGetConnectionPolicy() { - mPbapClientBinder.getConnectionPolicy(mTestDevice, mAttributionSource); + mPbapClientServiceBinder.getConnectionPolicy(mTestDevice, mAttributionSource); verify(mMockService).getConnectionPolicy(eq(mTestDevice)); } @@ -127,52 +129,54 @@ public class PbapClientBinderTest { @Test public void testConnect_afterCleanup_returnsFalse() { - mPbapClientBinder.cleanup(); - boolean result = mPbapClientBinder.connect(mTestDevice, mAttributionSource); + mPbapClientServiceBinder.cleanup(); + boolean result = mPbapClientServiceBinder.connect(mTestDevice, mAttributionSource); verify(mMockService, never()).connect(any(BluetoothDevice.class)); assertThat(result).isFalse(); } @Test public void testDisconnect_afterCleanup_returnsFalse() { - mPbapClientBinder.cleanup(); - boolean result = mPbapClientBinder.disconnect(mTestDevice, mAttributionSource); + mPbapClientServiceBinder.cleanup(); + boolean result = mPbapClientServiceBinder.disconnect(mTestDevice, mAttributionSource); verify(mMockService, never()).disconnect(any(BluetoothDevice.class)); assertThat(result).isFalse(); } @Test public void testGetConnectedDevices_afterCleanup_returnsEmptyList() { - mPbapClientBinder.cleanup(); - List<BluetoothDevice> devices = mPbapClientBinder.getConnectedDevices(mAttributionSource); + mPbapClientServiceBinder.cleanup(); + List<BluetoothDevice> devices = + mPbapClientServiceBinder.getConnectedDevices(mAttributionSource); verify(mMockService, never()).getConnectedDevices(); assertThat(devices).isEmpty(); } @Test public void testGetDevicesMatchingConnectionStates_afterCleanup_returnsEmptyList() { - mPbapClientBinder.cleanup(); + mPbapClientServiceBinder.cleanup(); int[] states = new int[] {STATE_CONNECTED}; List<BluetoothDevice> devices = - mPbapClientBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); + mPbapClientServiceBinder.getDevicesMatchingConnectionStates( + states, mAttributionSource); verify(mMockService, never()).getDevicesMatchingConnectionStates(any(int[].class)); assertThat(devices).isEmpty(); } @Test public void testGetConnectionState_afterCleanup_returnsDisconnected() { - mPbapClientBinder.cleanup(); - int state = mPbapClientBinder.getConnectionState(mTestDevice, mAttributionSource); + mPbapClientServiceBinder.cleanup(); + int state = mPbapClientServiceBinder.getConnectionState(mTestDevice, mAttributionSource); verify(mMockService, never()).getConnectionState(any(BluetoothDevice.class)); assertThat(state).isEqualTo(STATE_DISCONNECTED); } @Test public void testSetConnectionPolicy_afterCleanup_returnsFalse() { - mPbapClientBinder.cleanup(); + mPbapClientServiceBinder.cleanup(); int connectionPolicy = CONNECTION_POLICY_ALLOWED; boolean result = - mPbapClientBinder.setConnectionPolicy( + mPbapClientServiceBinder.setConnectionPolicy( mTestDevice, connectionPolicy, mAttributionSource); verify(mMockService, never()).setConnectionPolicy(any(BluetoothDevice.class), anyInt()); assertThat(result).isFalse(); @@ -180,8 +184,8 @@ public class PbapClientBinderTest { @Test public void testGetConnectionPolicy_afterCleanup_returnsUnknown() { - mPbapClientBinder.cleanup(); - int result = mPbapClientBinder.getConnectionPolicy(mTestDevice, mAttributionSource); + mPbapClientServiceBinder.cleanup(); + int result = mPbapClientServiceBinder.getConnectionPolicy(mTestDevice, mAttributionSource); verify(mMockService, never()).getConnectionPolicy(any(BluetoothDevice.class)); assertThat(result).isEqualTo(CONNECTION_POLICY_UNKNOWN); } diff --git a/android/app/tests/unit/src/com/android/bluetooth/sap/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/sap/OWNERS deleted file mode 100644 index 8f87191393..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/sap/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_content
\ No newline at end of file diff --git a/android/app/tests/unit/src/com/android/bluetooth/sap/SapServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/sap/SapServiceBinderTest.java new file mode 100644 index 0000000000..10d1a092e0 --- /dev/null +++ b/android/app/tests/unit/src/com/android/bluetooth/sap/SapServiceBinderTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.sap; + +import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; +import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; + +import static com.android.bluetooth.TestUtils.MockitoRule; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothDevice; +import android.content.AttributionSource; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +/** Test cases for {@link SapServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class SapServiceBinderTest { + + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); + + @Mock private SapService mService; + + private AttributionSource mAttributionSource; + private SapServiceBinder mBinder; + + @Before + public void setUp() throws Exception { + when(mService.isAvailable()).thenReturn(true); + mBinder = new SapServiceBinder(mService); + mAttributionSource = new AttributionSource.Builder(1).build(); + } + + @Test + public void getState() { + mBinder.getState(mAttributionSource); + verify(mService).getState(); + } + + @Test + public void getClient() { + mBinder.getClient(mAttributionSource); + // times(2) due to the Log + verify(mService, times(2)).getRemoteDevice(); + } + + @Test + public void isConnected() { + BluetoothDevice device = mock(BluetoothDevice.class); + + mBinder.isConnected(device, mAttributionSource); + verify(mService).getConnectionState(device); + } + + @Test + public void disconnect() { + BluetoothDevice device = mock(BluetoothDevice.class); + + mBinder.disconnect(device, mAttributionSource); + verify(mService).disconnect(device); + } + + @Test + public void getConnectedDevices() { + mBinder.getConnectedDevices(mAttributionSource); + verify(mService).getConnectedDevices(); + } + + @Test + public void getDevicesMatchingConnectionStates() { + int[] states = new int[] {STATE_CONNECTED, STATE_DISCONNECTED}; + + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); + verify(mService).getDevicesMatchingConnectionStates(states); + } + + @Test + public void getConnectionState() { + BluetoothDevice device = mock(BluetoothDevice.class); + + mBinder.getConnectionState(device, mAttributionSource); + verify(mService).getConnectionState(device); + } + + @Test + public void setConnectionPolicy() { + BluetoothDevice device = mock(BluetoothDevice.class); + int connectionPolicy = 1; + + mBinder.setConnectionPolicy(device, connectionPolicy, mAttributionSource); + verify(mService).setConnectionPolicy(device, connectionPolicy); + } + + @Test + public void getConnectionPolicy() { + BluetoothDevice device = mock(BluetoothDevice.class); + + mBinder.getConnectionPolicy(device, mAttributionSource); + verify(mService).getConnectionPolicy(device); + } + + @Test + public void cleanup_doesNotCrash() { + mBinder.cleanup(); + } +} diff --git a/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsServiceBinderTest.java new file mode 100644 index 0000000000..7758d101b1 --- /dev/null +++ b/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsServiceBinderTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.tbs; + +import static com.android.bluetooth.TestUtils.MockitoRule; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothLeCall; +import android.bluetooth.IBluetoothLeCallControlCallback; +import android.content.AttributionSource; +import android.os.ParcelUuid; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** Test cases for {@link TbsServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class TbsServiceBinderTest { + + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); + + @Mock private TbsService mService; + + private AttributionSource mAttributionSource; + private TbsServiceBinder mBinder; + + @Before + public void setUp() throws Exception { + when(mService.isAvailable()).thenReturn(true); + mBinder = new TbsServiceBinder(mService); + mAttributionSource = new AttributionSource.Builder(1).build(); + } + + @Test + public void registerBearer() { + String token = "token"; + IBluetoothLeCallControlCallback callback = mock(IBluetoothLeCallControlCallback.class); + String uci = "uci"; + List<String> uriSchemes = new ArrayList<>(); + int capabilities = 1; + String providerName = "providerName"; + int technology = 2; + + mBinder.registerBearer( + token, + callback, + uci, + uriSchemes, + capabilities, + providerName, + technology, + mAttributionSource); + verify(mService) + .registerBearer( + token, callback, uci, uriSchemes, capabilities, providerName, technology); + } + + @Test + public void unregisterBearer() { + String token = "token"; + + mBinder.unregisterBearer(token, mAttributionSource); + verify(mService).unregisterBearer(token); + } + + @Test + public void requestResult() { + int ccid = 1; + int requestId = 2; + int result = 3; + + mBinder.requestResult(ccid, requestId, result, mAttributionSource); + verify(mService).requestResult(ccid, requestId, result); + } + + @Test + public void callAdded() { + int ccid = 1; + BluetoothLeCall call = mock(BluetoothLeCall.class); + + mBinder.callAdded(ccid, call, mAttributionSource); + verify(mService).callAdded(ccid, call); + } + + @Test + public void callRemoved() { + int ccid = 1; + UUID callId = UUID.randomUUID(); + int reason = 2; + + mBinder.callRemoved(ccid, new ParcelUuid(callId), reason, mAttributionSource); + verify(mService).callRemoved(ccid, callId, reason); + } + + @Test + public void callStateChanged() { + int ccid = 1; + UUID callId = UUID.randomUUID(); + int state = 2; + + mBinder.callStateChanged(ccid, new ParcelUuid(callId), state, mAttributionSource); + verify(mService).callStateChanged(ccid, callId, state); + } + + @Test + public void currentCallsList() { + int ccid = 1; + List<BluetoothLeCall> calls = new ArrayList<>(); + + mBinder.currentCallsList(ccid, calls, mAttributionSource); + verify(mService).currentCallsList(ccid, calls); + } + + @Test + public void cleanup_doesNotCrash() { + mBinder.cleanup(); + } +} diff --git a/android/app/tests/unit/src/com/android/bluetooth/vc/OWNERS b/android/app/tests/unit/src/com/android/bluetooth/vc/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/app/tests/unit/src/com/android/bluetooth/vc/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceBinderTest.java new file mode 100644 index 0000000000..32296381c8 --- /dev/null +++ b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceBinderTest.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bluetooth.vc; + +import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; + +import static com.android.bluetooth.TestUtils.MockitoRule; +import static com.android.bluetooth.TestUtils.getTestDevice; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.IAudioInputCallback; +import android.content.AttributionSource; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +/** Test cases for {@link VolumeControlServiceBinder} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class VolumeControlServiceBinderTest { + + @Rule public final MockitoRule mMockitoRule = new MockitoRule(); + + @Mock private VolumeControlService mService; + + private final BluetoothDevice mDevice = getTestDevice(25); + + private AttributionSource mAttributionSource; + private VolumeControlServiceBinder mBinder; + + @Before + public void setUp() throws Exception { + when(mService.isAvailable()).thenReturn(true); + mBinder = new VolumeControlServiceBinder(mService); + mAttributionSource = new AttributionSource.Builder(1).build(); + } + + @Test + public void getConnectedDevices() { + mBinder.getConnectedDevices(mAttributionSource); + verify(mService).getConnectedDevices(); + } + + @Test + public void getDevicesMatchingConnectionStates() { + int[] states = new int[] {STATE_CONNECTED}; + + mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource); + verify(mService).getDevicesMatchingConnectionStates(states); + } + + @Test + public void getConnectionState() { + mBinder.getConnectionState(mDevice, mAttributionSource); + verify(mService).getConnectionState(mDevice); + } + + @Test + public void setConnectionPolicy() { + int connectionPolicy = 1; + + mBinder.setConnectionPolicy(mDevice, connectionPolicy, mAttributionSource); + verify(mService).setConnectionPolicy(mDevice, connectionPolicy); + } + + @Test + public void getConnectionPolicy() { + mBinder.getConnectionPolicy(mDevice, mAttributionSource); + verify(mService).getConnectionPolicy(mDevice); + } + + @Test + public void isVolumeOffsetAvailable() { + mBinder.isVolumeOffsetAvailable(mDevice, mAttributionSource); + verify(mService).isVolumeOffsetAvailable(mDevice); + } + + @Test + public void getNumberOfVolumeOffsetInstances() { + mBinder.getNumberOfVolumeOffsetInstances(mDevice, mAttributionSource); + verify(mService).getNumberOfVolumeOffsetInstances(mDevice); + } + + @Test + public void setVolumeOffset() { + int instanceId = 1; + int volumeOffset = 2; + + mBinder.setVolumeOffset(mDevice, instanceId, volumeOffset, mAttributionSource); + verify(mService).setVolumeOffset(mDevice, instanceId, volumeOffset); + } + + @Test + public void setDeviceVolume() { + int volume = 1; + boolean isGroupOp = true; + + mBinder.setDeviceVolume(mDevice, volume, isGroupOp, mAttributionSource); + verify(mService).setDeviceVolume(mDevice, volume, isGroupOp); + } + + @Test + public void setGroupVolume() { + int groupId = 1; + int volume = 2; + + mBinder.setGroupVolume(groupId, volume, mAttributionSource); + verify(mService).setGroupVolume(groupId, volume); + } + + @Test + public void getGroupVolume() { + int groupId = 1; + + mBinder.getGroupVolume(groupId, mAttributionSource); + verify(mService).getGroupVolume(groupId); + } + + @Test + public void setGroupActive() { + int groupId = 1; + boolean active = true; + + mBinder.setGroupActive(groupId, active, mAttributionSource); + verify(mService).setGroupActive(groupId, active); + } + + @Test + public void mute() { + mBinder.mute(mDevice, mAttributionSource); + verify(mService).mute(mDevice); + } + + @Test + public void muteGroup() { + int groupId = 1; + mBinder.muteGroup(groupId, mAttributionSource); + verify(mService).muteGroup(groupId); + } + + @Test + public void unmute() { + mBinder.unmute(mDevice, mAttributionSource); + verify(mService).unmute(mDevice); + } + + @Test + public void unmuteGroup() { + int groupId = 1; + + mBinder.unmuteGroup(groupId, mAttributionSource); + verify(mService).unmuteGroup(groupId); + } + + @Test + public void getNumberOfAudioInputControlServices() { + mBinder.getNumberOfAudioInputControlServices(mAttributionSource, mDevice); + } + + @Test + public void registerAudioInputControlCallback() { + int instanceId = 1; + IAudioInputCallback callback = mock(IAudioInputCallback.class); + + mBinder.registerAudioInputControlCallback( + mAttributionSource, mDevice, instanceId, callback); + } + + @Test + public void unregisterAudioInputControlCallback() { + int instanceId = 1; + IAudioInputCallback callback = mock(IAudioInputCallback.class); + + mBinder.unregisterAudioInputControlCallback( + mAttributionSource, mDevice, instanceId, callback); + } + + @Test + public void getAudioInputGainSettingUnit() { + int instanceId = 1; + mBinder.getAudioInputGainSettingUnit(mAttributionSource, mDevice, instanceId); + } + + @Test + public void getAudioInputGainSettingMin() { + int instanceId = 1; + mBinder.getAudioInputGainSettingMin(mAttributionSource, mDevice, instanceId); + } + + @Test + public void getAudioInputGainSettingMax() { + int instanceId = 1; + mBinder.getAudioInputGainSettingMax(mAttributionSource, mDevice, instanceId); + } + + @Test + public void getAudioInputDescription() { + int instanceId = 1; + mBinder.getAudioInputDescription(mAttributionSource, mDevice, instanceId); + } + + @Test + public void isAudioInputDescriptionWritable() { + int instanceId = 1; + mBinder.isAudioInputDescriptionWritable(mAttributionSource, mDevice, instanceId); + } + + @Test + public void setAudioInputDescription() { + int instanceId = 1; + String description = "test"; + mBinder.setAudioInputDescription(mAttributionSource, mDevice, instanceId, description); + } + + @Test + public void getAudioInputStatus() { + int instanceId = 1; + mBinder.getAudioInputStatus(mAttributionSource, mDevice, instanceId); + } + + @Test + public void getAudioInputType() { + int instanceId = 1; + mBinder.getAudioInputType(mAttributionSource, mDevice, instanceId); + } + + @Test + public void getAudioInputGainSetting() { + int instanceId = 1; + mBinder.getAudioInputGainSetting(mAttributionSource, mDevice, instanceId); + } + + @Test + public void setAudioInputGainSetting() { + int instanceId = 1; + int gainSetting = 2; + mBinder.setAudioInputGainSetting(mAttributionSource, mDevice, instanceId, gainSetting); + } + + @Test + public void getAudioInputGainMode() { + int instanceId = 1; + mBinder.getAudioInputGainMode(mAttributionSource, mDevice, instanceId); + } + + @Test + public void setAudioInputGainMode() { + int instanceId = 1; + int gainMode = 2; + mBinder.setAudioInputGainMode(mAttributionSource, mDevice, instanceId, gainMode); + } + + @Test + public void getAudioInputMute() { + int instanceId = 1; + mBinder.getAudioInputMute(mAttributionSource, mDevice, instanceId); + } + + @Test + public void setAudioInputMute() { + int instanceId = 1; + int mute = 2; + mBinder.setAudioInputMute(mAttributionSource, mDevice, instanceId, mute); + } + + @Test + public void cleanup_doesNotCrash() { + mBinder.cleanup(); + } +} diff --git a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java index 35d8ee3ce1..9412ebfe40 100644 --- a/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java +++ b/android/app/tests/unit/src/com/android/bluetooth/vc/VolumeControlServiceTest.java @@ -128,7 +128,7 @@ public class VolumeControlServiceTest { private AttributionSource mAttributionSource; private VolumeControlService mService; - private VolumeControlService.BluetoothVolumeControlBinder mBinder; + private VolumeControlServiceBinder mBinder; private InOrder mInOrder; private TestLooper mLooper; @@ -174,7 +174,7 @@ public class VolumeControlServiceTest { mService.setAvailable(true); mService.mFactory = mServiceFactory; - mBinder = (VolumeControlService.BluetoothVolumeControlBinder) mService.initBinder(); + mBinder = (VolumeControlServiceBinder) mService.initBinder(); } @After diff --git a/android/leaudio/OWNERS b/android/leaudio/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/android/leaudio/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/android/pandora/OWNERS b/android/pandora/OWNERS deleted file mode 100644 index c199a82a60..0000000000 --- a/android/pandora/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# Bug component: 1099313 -girardier@google.com diff --git a/android/pandora/test/main.py b/android/pandora/test/main.py index d5c5da0bad..7e49321932 100644 --- a/android/pandora/test/main.py +++ b/android/pandora/test/main.py @@ -25,6 +25,7 @@ import avatar.cases.security_test import gatt_test import hap_test import hfpclient_test +import rfcomm_test import sdp_test from pairing import _test_class_list as _pairing_test_class_list @@ -81,6 +82,7 @@ _TEST_CLASSES_LIST = [ hap_test.HapTest, asha_test.AshaTest, hfpclient_test.HfpClientTest, + rfcomm_test.RfcommTest, ] + _pairing_test_class_list diff --git a/android/pandora/test/pairing/OWNERS b/android/pandora/test/pairing/OWNERS deleted file mode 100644 index b430ae987d..0000000000 --- a/android/pandora/test/pairing/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# Bug component: 27441 -rwt@google.com diff --git a/android/pandora/test/rfcomm_test.py b/android/pandora/test/rfcomm_test.py new file mode 100644 index 0000000000..4409b02e25 --- /dev/null +++ b/android/pandora/test/rfcomm_test.py @@ -0,0 +1,110 @@ +# Copyright 2025 Google LLC +# +# 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 +# +# https://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. + +import asyncio +import avatar +import grpc +import logging + +from avatar import PandoraDevices +from avatar.aio import asynchronous +from avatar.pandora_client import BumblePandoraClient, PandoraClient +from bumble.rfcomm import Server +from bumble_experimental.rfcomm import RFCOMMService +from mobly import base_test, test_runner +from mobly.asserts import assert_equal # type: ignore +from mobly.asserts import assert_in # type: ignore +from mobly.asserts import assert_is_not_none # type: ignore +from mobly.asserts import fail # type: ignore +from pandora_experimental.rfcomm_grpc_aio import RFCOMM +from pandora_experimental.rfcomm_pb2 import ( + AcceptConnectionRequest, + RxRequest, + StartServerRequest, + StopServerRequest, + TxRequest, +) +from typing import Optional, Tuple + +SERIAL_PORT_UUID = "00001101-0000-1000-8000-00805F9B34FB" +TEST_SERVER_NAME = "RFCOMM-Server" + + +class RfcommTest(base_test.BaseTestClass): + devices: Optional[PandoraDevices] = None + dut: PandoraClient + ref: BumblePandoraClient + + def setup_class(self) -> None: + self.devices = PandoraDevices(self) + self.dut, ref, *_ = self.devices + assert isinstance(ref, BumblePandoraClient) + self.ref = ref + # Enable BR/EDR mode and SSP for Bumble devices. + self.ref.config.setdefault('classic_enabled', True) + self.ref.config.setdefault('classic_ssp_enabled', True) + self.ref.config.setdefault( + 'server', + { + 'io_capability': 'no_output_no_input', + }, + ) + + def teardown_class(self) -> None: + if self.devices: + self.devices.stop_all() + + @avatar.asynchronous + async def setup_test(self) -> None: + await asyncio.gather(self.dut.reset(), self.ref.reset()) + + ref_server = Server(self.ref.device) + self.ref.rfcomm = RFCOMMService(self.ref.device, ref_server) + self.dut.rfcomm = RFCOMM(channel=self.dut.aio.channel) + + @avatar.asynchronous + async def test_client_connect_and_exchange_data(self) -> None: + # dut is client, ref is server + context = grpc.ServicerContext + server = await self.ref.rfcomm.StartServer(StartServerRequest(name=TEST_SERVER_NAME, uuid=SERIAL_PORT_UUID), + context=context) + # Convert StartServerResponse to its server + server = server.server + rfc_dut_ref, rfc_ref_dut = await asyncio.gather( + self.dut.rfcomm.ConnectToServer(address=self.ref.address, uuid=SERIAL_PORT_UUID), + self.ref.rfcomm.AcceptConnection(request=AcceptConnectionRequest(server=server), context=context)) + # Convert Responses to their corresponding RfcommConnection + rfc_dut_ref = rfc_dut_ref.connection + rfc_ref_dut = rfc_ref_dut.connection + + # Transmit data + tx_data = b'Data from dut to ref' + await self.dut.rfcomm.Send(data=tx_data, connection=rfc_dut_ref) + ref_receive = await self.ref.rfcomm.Receive(request=RxRequest(connection=rfc_ref_dut), context=context) + assert_equal(ref_receive.data, tx_data) + + # Receive data + rx_data = b'Data from ref to dut' + await self.ref.rfcomm.Send(request=TxRequest(connection=rfc_ref_dut, data=rx_data), context=context) + dut_receive = await self.dut.rfcomm.Receive(connection=rfc_dut_ref) + assert_equal(dut_receive.data.rstrip(b'\x00'), rx_data) + + # Disconnect (from dut) + await self.dut.rfcomm.Disconnect(connection=rfc_dut_ref) + await self.ref.rfcomm.StopServer(request=StopServerRequest(server=server), context=context) + + +if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG) + test_runner.main() # type: ignore diff --git a/apex/Android.bp b/apex/Android.bp index c2aabcf0b8..bf75163768 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -84,7 +84,6 @@ apex { ], key: "com.android.bt.key", certificate: ":com.android.bt.certificate", - updatable: true, compressible: false, visibility: ["//packages/modules/common/build"], } diff --git a/apex/OWNERS b/apex/OWNERS deleted file mode 100644 index cc88477d0e..0000000000 --- a/apex/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -# Reviewers for /apex - -wescande@google.com - diff --git a/apex/hiddenapi/OWNERS b/apex/hiddenapi/OWNERS deleted file mode 100644 index ac8a2b627c..0000000000 --- a/apex/hiddenapi/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -# soong-team@ as the hiddenapi files are tightly coupled with Soong -file:platform/build/soong:/OWNERS - -# compat-team@ for changes to hiddenapi files -file:tools/platform-compat:/OWNERS diff --git a/apex/permissions/OWNERS b/apex/permissions/OWNERS deleted file mode 100644 index 8b8ec67028..0000000000 --- a/apex/permissions/OWNERS +++ /dev/null @@ -1 +0,0 @@ -per-file *.xml,OWNERS = file:platform/frameworks/base:/data/etc/OWNERS @@ -86,7 +86,6 @@ HOST_TESTS = [ # 'bluetooth_test_common', # 'bluetoothtbd_test', # 'net_test_avrcp', - # 'net_test_btcore', # 'net_test_types', # 'net_test_btm_iso', # 'net_test_btpackets', diff --git a/common/OWNERS b/common/OWNERS deleted file mode 100644 index 5b3f4bad26..0000000000 --- a/common/OWNERS +++ /dev/null @@ -1 +0,0 @@ -wescande@google.com diff --git a/flags/OWNERS b/flags/OWNERS deleted file mode 100644 index b4f2f7376b..0000000000 --- a/flags/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# Bug component: 1387432 -girardier@google.com -wescande@google.com diff --git a/flags/a2dp.aconfig b/flags/a2dp.aconfig index e7b9aa21b0..1fd8bbd085 100644 --- a/flags/a2dp.aconfig +++ b/flags/a2dp.aconfig @@ -115,3 +115,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "avdtp_prevent_double_suspend" + namespace: "bluetooth" + description: "Add state to prevent sending multiple AVDTP Suspend command in a row" + bug: "402241316" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/bta_dm.aconfig b/flags/bta_dm.aconfig index 19e8418785..be510f63cd 100644 --- a/flags/bta_dm.aconfig +++ b/flags/bta_dm.aconfig @@ -9,16 +9,6 @@ flag { } flag { - name: "cancel_open_discovery_client" - namespace: "bluetooth" - description: "Cancel connection from discovery client correctly" - bug: "356168480" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "extend_and_randomize_role_switch_delay" namespace: "bluetooth" description: "Fix the possible conflicts between role switch and authentication" diff --git a/flags/connectivity.aconfig b/flags/connectivity.aconfig index 482c7e68e8..738c294078 100644 --- a/flags/connectivity.aconfig +++ b/flags/connectivity.aconfig @@ -2,30 +2,6 @@ package: "com.android.bluetooth.flags" container: "com.android.bt" flag { - name: "api_get_connection_state_using_identity_address" - namespace: "bluetooth" - description: "Use identity address to check current connection state" - bug: "319471537" -} - -flag { - name: "use_le_shim_connection_map_guard" - namespace: "bluetooth" - description: "Guard the le shim connection map with a mutex" - bug: "302054609" -} - -flag { - name: "improve_create_connection_for_already_connecting_device" - namespace: "bluetooth" - description: "Make sure to not stop controller with create connection cancel when not needed" - bug: "356593752" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "allow_gatt_connect_from_the_apps_without_making_leaudio_device_active" namespace: "bluetooth" description: "Allows for GATT connection without making LeAudio device active after connection" diff --git a/flags/framework.aconfig b/flags/framework.aconfig index dc48541118..0151b46c70 100644 --- a/flags/framework.aconfig +++ b/flags/framework.aconfig @@ -10,16 +10,6 @@ flag { } flag { - name: "identity_address_null_if_not_known" - namespace: "bluetooth" - description: "Return null for identity address if identity address is not known" - bug: "317120534" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "support_bluetooth_quality_report_v6" is_exported: true namespace: "bluetooth" diff --git a/flags/gap.aconfig b/flags/gap.aconfig index d12e294ec7..9dcdcd4b2b 100644 --- a/flags/gap.aconfig +++ b/flags/gap.aconfig @@ -30,13 +30,6 @@ flag { } flag { - name: "ble_scan_adv_metrics_redesign" - namespace: "bluetooth" - description: "Reimplement BLE scan and advertisement metrics logging." - bug: "328303508" -} - -flag { name: "msft_addr_tracking_quirk" namespace: "bluetooth" description: "Scanning with MSFT paddress tracking for Realtek BT controllers" @@ -57,33 +50,6 @@ flag { } flag { - name: "gatt_client_dynamic_allocation" - namespace: "bluetooth" - description: "Allocate GATT clients in heap to unlimit the number of clients" - bug: "348559823" -} - -flag { - name: "gatt_fix_multiple_direct_connect" - namespace: "bluetooth" - description: "Do not remove device when multiple clients attempt to connect" - bug: "349232327" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { - name: "pan_use_identity_address" - namespace: "bluetooth" - description: "Use identity address when communicate with native interface" - bug: "351961492" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "android_os_identifier" namespace: "bluetooth" description: "Add a custom service to provide Android OS identifier" @@ -104,33 +70,6 @@ flag { } flag { - name: "non_wake_alarm_for_rpa_rotation" - namespace: "bluetooth" - description: "Use non-wake alarm for LE RPA rotation. go/non-wake-alarm-for-rpa-rotation" - bug: "360743527" -} - -flag { - name: "gatt_disconnect_fix" - namespace: "bluetooth" - description: "Fix GATT disconnect handling" - bug: "361538527" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { - name: "gatt_server_requests_fix" - namespace: "bluetooth" - description: "Fix GATT server handling" - bug: "361331170" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "le_scan_msft_support" namespace: "bluetooth" description: "Support MSFT HCI extension for LE Scanning. go/bt-msft-aosp-dd" @@ -206,16 +145,6 @@ flag { } flag { - name: "drop_acl_fragment_on_disconnect" - namespace: "bluetooth" - description: "Drop pending ACL packet fragments for disconnected connection" - bug: "376379859" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "configure_scan_on_resume" namespace: "bluetooth" description: "Configure scan paramters when start scanning from onResume" @@ -324,3 +253,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "le_disconnect_notification_handling" + namespace: "bluetooth" + description: "Fix LE link disconnection notification to stack's upper layers" + bug: "403433488" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/hci.aconfig b/flags/hci.aconfig index cdd5ca3ab6..6f6b1e70df 100644 --- a/flags/hci.aconfig +++ b/flags/hci.aconfig @@ -2,13 +2,6 @@ package: "com.android.bluetooth.flags" container: "com.android.bt" flag { - name: "encryption_change_v2" - namespace: "bluetooth" - description: "Enable encryption change V2 event" - bug: "366018699" -} - -flag { name: "dont_send_hci_disconnect_repeatedly" namespace: "bluetooth" description: "Prevent BT from sending repeated HCI disconnect command" diff --git a/flags/hfp.aconfig b/flags/hfp.aconfig index c1611242aa..9e3bd50b5d 100644 --- a/flags/hfp.aconfig +++ b/flags/hfp.aconfig @@ -132,3 +132,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "hfp_volume_control_property" + namespace: "bluetooth" + description: "Check system property before hands-free volume UI request." + bug: "404152232" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/hid.aconfig b/flags/hid.aconfig index d40e55821f..350367818b 100644 --- a/flags/hid.aconfig +++ b/flags/hid.aconfig @@ -20,16 +20,6 @@ flag { } flag { - name: "serialize_hogp_and_dis" - namespace: "bluetooth" - description: "start HOGP service discovery only after DIS discovery is finished" - bug: "367910199" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "dont_send_hid_set_idle" namespace: "bluetooth" description: "Don't send the SET IDLE HID message" @@ -40,16 +30,6 @@ flag { } flag { - name: "forward_get_set_report_failure_to_uhid" - namespace: "bluetooth" - description: "Forward GET/SET REPORT reply to UHID even when the request fails" - bug: "369748430" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "remove_pending_hid_connection" namespace: "bluetooth" description: "Remove the pending BTA HH connection instance when the device is removed" @@ -118,3 +98,23 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "hh_state_update_race_fix" + namespace: "bluetooth" + description: "Fix stuck in connecting state due to race when updating state" + bug: "403420458" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "simpler_hid_connection_policy" + namespace: "bluetooth" + description: "Simplify native HID host connection policy enforcement" + bug: "404590499" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/l2cap.aconfig b/flags/l2cap.aconfig index fec2edd6d5..f82b596674 100644 --- a/flags/l2cap.aconfig +++ b/flags/l2cap.aconfig @@ -9,16 +9,6 @@ flag { } flag { - name: "l2cap_le_do_not_adjust_min_interval" - namespace: "bluetooth" - description: "Do not adjust min_interval in connection update request" - bug: "346960036" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "l2cap_fcs_option_fix" namespace: "bluetooth" description: "Use fcs_option for non BASIC mode " diff --git a/flags/leaudio.aconfig b/flags/leaudio.aconfig index 9d2c86afa3..a2f77b5658 100644 --- a/flags/leaudio.aconfig +++ b/flags/leaudio.aconfig @@ -344,3 +344,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "leaudio_use_aggressive_params" + namespace: "bluetooth" + description: "use aggressive parameters for LE Audio device" + bug: "400607635" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/opp.aconfig b/flags/opp.aconfig index 73604961fe..cdba75b756 100644 --- a/flags/opp.aconfig +++ b/flags/opp.aconfig @@ -2,16 +2,6 @@ package: "com.android.bluetooth.flags" container: "com.android.bt" flag { - name: "opp_ignore_content_observer_after_service_stop" - namespace: "bluetooth" - description: "When OppService.stop() is called, previously posted ContentObserver.onChange() should not run" - bug: "346467641" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "opp_set_insets_for_edge_to_edge" namespace: "bluetooth" description: "Set proper insets in BluetoothOppTransferHistory to adapt to edge-to-edge." @@ -41,3 +31,20 @@ flag { } } +flag { + name: "opp_device_picker_extra_intent_apis" + is_exported: true + namespace: "bluetooth" + description: "New API to get the original intent in Bluetooth Device Picker" + bug: "395796600" +} + +flag { + name: "send_opp_device_picker_extra_intent" + namespace: "bluetooth" + description: "Send the original intent when opening Bluetooth device picker" + bug: "397852103" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/pairing.aconfig b/flags/pairing.aconfig index bc57bafe9e..faae7d2618 100644 --- a/flags/pairing.aconfig +++ b/flags/pairing.aconfig @@ -102,16 +102,6 @@ flag { } flag { - name: "smp_state_machine_stuck_after_disconnection_fix" - namespace: "bluetooth" - description: "Fix state machine stuck after pairing device disconnection" - bug: "376306092" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "prevent_service_connections_on_remove_bond" namespace: "bluetooth" description: "Disable service connections on remove bond" @@ -260,3 +250,33 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "le_peripheral_enc_failure" + namespace: "bluetooth" + description: "Don't remove bond on LE encryption failure in peripheral role with bonded device, instead just disconnect the link" + bug: "403313352" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "immediate_encryption_after_pairing" + namespace: "bluetooth" + description: "Encrypt BR/EDR link immediately after pairing" + bug: "402510244" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "unrelated_device_smp_cancellation" + namespace: "bluetooth" + description: "Don't cancel SMP pairing if encryption fails for unrelated device" + bug: "404658828" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/security.aconfig b/flags/security.aconfig index c83dc02b24..8d5a8c1f31 100644 --- a/flags/security.aconfig +++ b/flags/security.aconfig @@ -2,13 +2,6 @@ package: "com.android.bluetooth.flags" container: "com.android.bt" flag { - name: "key_missing_classic_device" - namespace: "bluetooth" - description: "Key missing broadcast for Classic devices" - bug: "333634398" -} - -flag { name: "key_missing_ble_peripheral" namespace: "bluetooth" description: "Key missing broadcast for LE devices in peripheral role" @@ -66,16 +59,6 @@ flag { } flag { - name: "sec_disconnect_on_le_key_missing" - namespace: "bluetooth" - description: "Disconnect LE link when keys are missing during encryption" - bug: "376680866" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "guard_bonded_device_properties" namespace: "bluetooth" description: "Don't update device properties for bonded devices from the device discovery results" diff --git a/flags/sockets.aconfig b/flags/sockets.aconfig index 2eb23b1fcb..6b31e06705 100644 --- a/flags/sockets.aconfig +++ b/flags/sockets.aconfig @@ -92,3 +92,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "fix_lecoc_socket_available" + namespace: "bluetooth" + description: "Fix Bluetooth Socket available API for LECOC socket" + bug: "402536099" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/system_service.aconfig b/flags/system_service.aconfig index ea40eb33de..c1cf4f6bd8 100644 --- a/flags/system_service.aconfig +++ b/flags/system_service.aconfig @@ -2,6 +2,16 @@ package: "com.android.bluetooth.flags" container: "com.android.bt" flag { + name: "enable_ble_while_disabling_airplane" + namespace: "bluetooth" + description: "Fix a race between enabling and handling airplane event" + bug: "402563502" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "kill_instead_of_exit" namespace: "bluetooth" description: "There is no value in pretending we are exiting properly. This is a kill and we should express it this way when finishing the process" diff --git a/floss/OWNERS b/floss/OWNERS deleted file mode 100644 index a823e6e1dd..0000000000 --- a/floss/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_chromeos diff --git a/floss/pandora/OWNERS b/floss/pandora/OWNERS deleted file mode 100644 index ca4001b6d4..0000000000 --- a/floss/pandora/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -# Reviewers for /floss/pandora - -johnlai@google.com -chharry@google.com diff --git a/framework/OWNERS b/framework/OWNERS deleted file mode 100644 index 40a43c47cb..0000000000 --- a/framework/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -hallstrom@google.com -okamil@google.com -siyuanh@google.com -wescande@google.com diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt index cdb9bf0670..ef922c92e1 100644 --- a/framework/api/system-current.txt +++ b/framework/api/system-current.txt @@ -369,6 +369,7 @@ package android.bluetooth { public interface BluetoothDevicePicker { field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_DEVICE_SELECTED = "android.bluetooth.devicepicker.action.DEVICE_SELECTED"; field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LAUNCH = "android.bluetooth.devicepicker.action.LAUNCH"; + field @FlaggedApi("com.android.bluetooth.flags.opp_device_picker_extra_intent_apis") public static final String EXTRA_DEVICE_PICKER_ORIGINAL_SEND_INTENT = "android.bluetooth.extra.DEVICE_PICKER_ORIGINAL_SEND_INTENT"; field public static final String EXTRA_FILTER_TYPE = "android.bluetooth.devicepicker.extra.FILTER_TYPE"; field public static final String EXTRA_LAUNCH_CLASS = "android.bluetooth.devicepicker.extra.DEVICE_PICKER_LAUNCH_CLASS"; field public static final String EXTRA_LAUNCH_PACKAGE = "android.bluetooth.devicepicker.extra.LAUNCH_PACKAGE"; diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 40d1153581..1b37497323 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3686,6 +3686,9 @@ public final class BluetoothAdapter { if (mBluetoothLeScanner != null) { mBluetoothLeScanner.cleanup(); } + if (mDistanceMeasurementManager != null) { + mDistanceMeasurementManager.cleanup(); + } } } finally { mServiceLock.writeLock().unlock(); diff --git a/framework/java/android/bluetooth/BluetoothDevicePicker.java b/framework/java/android/bluetooth/BluetoothDevicePicker.java index ee788dae18..7e7cd6d6b7 100644 --- a/framework/java/android/bluetooth/BluetoothDevicePicker.java +++ b/framework/java/android/bluetooth/BluetoothDevicePicker.java @@ -18,6 +18,7 @@ package android.bluetooth; import static android.Manifest.permission.BLUETOOTH_CONNECT; +import android.annotation.FlaggedApi; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -25,6 +26,8 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; +import com.android.bluetooth.flags.Flags; + /** * A helper to show a system "Device Picker" activity to the user. * @@ -64,6 +67,14 @@ public interface BluetoothDevicePicker { String EXTRA_LAUNCH_CLASS = "android.bluetooth.devicepicker.extra.DEVICE_PICKER_LAUNCH_CLASS"; /** + * Extra for the original ACTION_SEND or ACTION_SEND_MULTIPLE intent that triggered the BT + * sharing. + */ + @FlaggedApi(Flags.FLAG_OPP_DEVICE_PICKER_EXTRA_INTENT_APIS) + String EXTRA_DEVICE_PICKER_ORIGINAL_SEND_INTENT = + "android.bluetooth.extra.DEVICE_PICKER_ORIGINAL_SEND_INTENT"; + + /** * Broadcast when one BT device is selected from BT device picker screen. Selected {@link * BluetoothDevice} is returned in extra data named {@link BluetoothDevice#EXTRA_DEVICE}. */ diff --git a/framework/java/android/bluetooth/OWNERS b/framework/java/android/bluetooth/OWNERS deleted file mode 100644 index 757ed73819..0000000000 --- a/framework/java/android/bluetooth/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -per-file BluetoothHearingAid.java=file:/OWNERS_hearingaid -per-file BluetoothCsipSetCoordinator.java=file:/OWNERS_leaudio -per-file BluetoothLeAudio*.java=file:/OWNERS_leaudio -per-file BluetoothLeBroadcast*.java=file:/OWNERS_leaudio -per-file BluetoothVolumeControl.java=file:/OWNERS_leaudio diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementManager.java b/framework/java/android/bluetooth/le/DistanceMeasurementManager.java index 3b3c1126ff..94715301f0 100644 --- a/framework/java/android/bluetooth/le/DistanceMeasurementManager.java +++ b/framework/java/android/bluetooth/le/DistanceMeasurementManager.java @@ -24,6 +24,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresNoPermission; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; @@ -271,6 +272,16 @@ public final class DistanceMeasurementManager { return Collections.emptySet(); } + /** + * Clear session map. Should be called when bluetooth is down. + * + * @hide + */ + @RequiresNoPermission + public void cleanup() { + mSessionMap.clear(); + } + @SuppressLint("AndroidFrameworkBluetoothPermission") private final IDistanceMeasurementCallback mCallbackWrapper = new IDistanceMeasurementCallback.Stub() { diff --git a/framework/tests/bumble/src/android/bluetooth/DckScanTest.kt b/framework/tests/bumble/src/android/bluetooth/DckScanTest.kt index 8660a4076b..845862b71a 100644 --- a/framework/tests/bumble/src/android/bluetooth/DckScanTest.kt +++ b/framework/tests/bumble/src/android/bluetooth/DckScanTest.kt @@ -32,6 +32,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout import org.junit.Assume.assumeTrue +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -99,6 +100,7 @@ class DckScanTest( } @Test + @Ignore("b/404159990") fun scanForUuid_remoteFound() { // Assume isRemoteAdvertisingWithUuid is true to skip tests in which // device is not advertising with UUID diff --git a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java index 9b631dce91..6e6337279e 100644 --- a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java +++ b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java @@ -422,7 +422,6 @@ public class GattClientTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_GATT_FIX_MULTIPLE_DIRECT_CONNECT) public void connectMultiple_closeOne_shouldSuccess() { BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); BluetoothGattCallback gattCallback2 = mock(BluetoothGattCallback.class); @@ -435,11 +434,11 @@ public class GattClientTest { BluetoothGatt gatt2 = device.connectGatt(mContext, false, gattCallback2); try { - gatt.disconnect(); - gatt.close(); - verify(gattCallback2, timeout(1000)) .onConnectionStateChange(eq(gatt2), eq(GATT_SUCCESS), eq(STATE_CONNECTED)); + + gatt.disconnect(); + gatt.close(); } finally { gatt2.disconnect(); gatt2.close(); @@ -696,7 +695,6 @@ public class GattClientTest { // Check if we can have 100 simultaneous clients @Test - @RequiresFlagsEnabled(Flags.FLAG_GATT_CLIENT_DYNAMIC_ALLOCATION) public void connectGatt_multipleClients() { registerGattService(); diff --git a/framework/tests/bumble/src/android/bluetooth/hid/HidHeadTrackerTest.java b/framework/tests/bumble/src/android/bluetooth/hid/HidHeadTrackerTest.java index 38527362ba..3df5075936 100644 --- a/framework/tests/bumble/src/android/bluetooth/hid/HidHeadTrackerTest.java +++ b/framework/tests/bumble/src/android/bluetooth/hid/HidHeadTrackerTest.java @@ -64,6 +64,7 @@ import android.util.Log; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.bluetooth.flags.Flags; import com.android.compatibility.common.util.AdoptShellPermissionsRule; import org.hamcrest.CustomTypeSafeMatcher; @@ -353,6 +354,7 @@ public class HidHeadTrackerTest { BluetoothDevice.ACTION_UUID, BluetoothDevice.ACTION_ACL_CONNECTED, BluetoothDevice.ACTION_ACL_DISCONNECTED, + BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED, BluetoothDevice.ACTION_FOUND); } @@ -405,6 +407,7 @@ public class HidHeadTrackerTest { unregisterIntentActions( BluetoothDevice.ACTION_UUID, BluetoothDevice.ACTION_ACL_CONNECTED, + BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED, BluetoothDevice.ACTION_FOUND); } @@ -490,8 +493,10 @@ public class HidHeadTrackerTest { */ private void verifyTransportSwitch(BluetoothDevice device, int fromTransport, int toTransport) { assertThat(fromTransport).isNotEqualTo(toTransport); - verifyConnectionState(mBumbleDevice, equalTo(fromTransport), equalTo(STATE_DISCONNECTING)); - + if (!Flags.ignoreUnselectedHidTransportStates()) { + verifyConnectionState( + mBumbleDevice, equalTo(fromTransport), equalTo(STATE_DISCONNECTING)); + } // Capture the next intent with filter // Filter is necessary as otherwise it will corrupt all other unordered verifications final Intent[] savedIntent = {null}; diff --git a/framework/tests/bumble/src/android/bluetooth/hid/HidHostDualModeTest.java b/framework/tests/bumble/src/android/bluetooth/hid/HidHostDualModeTest.java index fb89c738ad..45c329e460 100644 --- a/framework/tests/bumble/src/android/bluetooth/hid/HidHostDualModeTest.java +++ b/framework/tests/bumble/src/android/bluetooth/hid/HidHostDualModeTest.java @@ -66,6 +66,7 @@ import android.util.Log; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.bluetooth.flags.Flags; import com.android.compatibility.common.util.AdoptShellPermissionsRule; import org.hamcrest.CustomTypeSafeMatcher; @@ -503,8 +504,9 @@ public class HidHostDualModeTest { */ private void verifyTransportSwitch(BluetoothDevice device, int fromTransport, int toTransport) { assertThat(fromTransport).isNotEqualTo(toTransport); - verifyConnectionState(mDevice, equalTo(fromTransport), equalTo(STATE_DISCONNECTING)); - + if (!Flags.ignoreUnselectedHidTransportStates()) { + verifyConnectionState(mDevice, equalTo(fromTransport), equalTo(STATE_DISCONNECTING)); + } // Capture the next intent with filter // Filter is necessary as otherwise it will corrupt all other unordered verifications final Intent[] savedIntent = {null}; diff --git a/framework/tests/bumble/src/android/bluetooth/hid/OWNERS b/framework/tests/bumble/src/android/bluetooth/hid/OWNERS deleted file mode 100644 index 75539edb09..0000000000 --- a/framework/tests/bumble/src/android/bluetooth/hid/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# Bug component: 27441 -# Project owners -rwt@google.com diff --git a/framework/tests/bumble/src/android/bluetooth/pairing/OWNERS b/framework/tests/bumble/src/android/bluetooth/pairing/OWNERS deleted file mode 100644 index 75539edb09..0000000000 --- a/framework/tests/bumble/src/android/bluetooth/pairing/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# Bug component: 27441 -# Project owners -rwt@google.com diff --git a/framework/tests/bumble/src/android/bluetooth/pairing/OobPairingTest.java b/framework/tests/bumble/src/android/bluetooth/pairing/OobPairingTest.java index bdfa42dd65..0b0da56f7b 100644 --- a/framework/tests/bumble/src/android/bluetooth/pairing/OobPairingTest.java +++ b/framework/tests/bumble/src/android/bluetooth/pairing/OobPairingTest.java @@ -19,6 +19,8 @@ package android.bluetooth.pairing; import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction; import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra; +import static com.google.common.truth.Truth.assertThat; + import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter.OobDataCallback; import android.bluetooth.BluetoothDevice; @@ -340,11 +342,14 @@ public class OobPairingTest { while (true) { if (scanningResponseIterator.hasNext()) { ScanningResponse scanningResponse = scanningResponseIterator.next(); - // select first available device + // select first available device with Random address type deviceAddr = scanningResponse.getRandom(); - break; + if (deviceAddr != null) { + break; + } } } + assertThat(deviceAddr).isNotNull(); ConnectLEResponse leConn = mBumble.hostBlocking() diff --git a/framework/tests/bumble/src/android/bluetooth/service_discovery/OWNERS b/framework/tests/bumble/src/android/bluetooth/service_discovery/OWNERS deleted file mode 100644 index 353b5d03a5..0000000000 --- a/framework/tests/bumble/src/android/bluetooth/service_discovery/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# Bug component: 27441 -# Project owners -jpawlowski@google.com diff --git a/framework/tests/bumble/src/android/bluetooth/sockets/OWNERS b/framework/tests/bumble/src/android/bluetooth/sockets/OWNERS deleted file mode 100644 index f9b588d2e9..0000000000 --- a/framework/tests/bumble/src/android/bluetooth/sockets/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# Project owners -bhaktha@google.com -poahlo@google.com diff --git a/framework/tests/metrics/OWNERS b/framework/tests/metrics/OWNERS deleted file mode 100644 index 01d41baf7e..0000000000 --- a/framework/tests/metrics/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# Bug component: 1099313 -# Project owners -ahujapalash@google.com diff --git a/offload/leaudio/hci/proxy.rs b/offload/leaudio/hci/proxy.rs index 933389d315..adc2dbd34d 100644 --- a/offload/leaudio/hci/proxy.rs +++ b/offload/leaudio/hci/proxy.rs @@ -195,10 +195,16 @@ impl Module for LeAudioModule { ); } - Ok(Command::LeSetupIsoDataPath(ref c)) if c.data_path_id == DATA_PATH_ID_SOFTWARE => { + Ok(Command::LeSetupIsoDataPath(ref c)) if c.data_path_id == DATA_PATH_ID_SOFTWARE => 'command: { assert_eq!(c.data_path_direction, hci::LeDataPathDirection::Input); let mut state = self.state.lock().unwrap(); - let stream = state.stream.get_mut(&c.connection_handle).unwrap(); + let Some(stream) = state.stream.get_mut(&c.connection_handle) else { + log::warn!( + "Setup ISO Data Path on non existing BIS/CIS handle: 0x{:03x}", + c.connection_handle + ); + break 'command; + }; stream.state = StreamState::Enabling; // Phase 1 limitation: The controller does not implement HCI Link Feedback event, @@ -209,6 +215,16 @@ impl Module for LeAudioModule { return; } + Ok(Command::LeRemoveIsoDataPath(ref c)) => { + let mut state = self.state.lock().unwrap(); + if state.stream.get_mut(&c.connection_handle).is_none() { + log::warn!( + "Remove ISO Data Path on non existing BIS/CIS handle: 0x{:03x}", + c.connection_handle + ); + } + } + _ => (), } @@ -250,7 +266,9 @@ impl Module for LeAudioModule { ReturnParameters::LeSetupIsoDataPath(ref ret) => 'event: { let mut state = self.state.lock().unwrap(); - let stream = state.stream.get_mut(&ret.connection_handle).unwrap(); + let Some(stream) = state.stream.get_mut(&ret.connection_handle) else { + break 'event; + }; stream.state = if stream.state == StreamState::Enabling && ret.status == Status::Success { StreamState::Enabled @@ -278,9 +296,11 @@ impl Module for LeAudioModule { ); } - ReturnParameters::LeRemoveIsoDataPath(ref ret) if ret.status == Status::Success => { + ReturnParameters::LeRemoveIsoDataPath(ref ret) if ret.status == Status::Success => 'event: { let mut state = self.state.lock().unwrap(); - let stream = state.stream.get_mut(&ret.connection_handle).unwrap(); + let Some(stream) = state.stream.get_mut(&ret.connection_handle) else { + break 'event; + }; if stream.state == StreamState::Enabled { Service::stop_stream(ret.connection_handle); } diff --git a/pandora/OWNERS b/pandora/OWNERS deleted file mode 100644 index 14634f3b78..0000000000 --- a/pandora/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# Project owners -girardier@google.com diff --git a/service/OWNERS b/service/OWNERS deleted file mode 100644 index 5b3f4bad26..0000000000 --- a/service/OWNERS +++ /dev/null @@ -1 +0,0 @@ -wescande@google.com diff --git a/service/src/com/android/server/bluetooth/BluetoothManagerService.java b/service/src/com/android/server/bluetooth/BluetoothManagerService.java index 08a949d81a..b797d6ceac 100644 --- a/service/src/com/android/server/bluetooth/BluetoothManagerService.java +++ b/service/src/com/android/server/bluetooth/BluetoothManagerService.java @@ -78,7 +78,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.sysprop.BluetoothProperties; -import android.util.proto.ProtoOutputStream; import androidx.annotation.RequiresApi; @@ -95,7 +94,6 @@ import kotlin.Unit; import kotlin.time.TimeSource; import java.io.FileDescriptor; -import java.io.FileOutputStream; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -140,10 +138,17 @@ class BluetoothManagerService { // Delay for retrying enable and disable in msec @VisibleForTesting static final int ENABLE_DISABLE_DELAY_MS = 300 * HW_MULTIPLIER; + // TODO: b/402209603 remove along with system_server_remove_extra_thread_jump @VisibleForTesting static final int MESSAGE_ENABLE = 1; + // TODO: b/402209603 remove along with system_server_remove_extra_thread_jump @VisibleForTesting static final int MESSAGE_DISABLE = 2; + + // TODO: b/402209603 remove along with system_server_remove_extra_thread_jump @VisibleForTesting static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3; + + // TODO: b/402209603 remove along with system_server_remove_extra_thread_jump @VisibleForTesting static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4; + @VisibleForTesting static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; @VisibleForTesting static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; @VisibleForTesting static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42; @@ -327,8 +332,9 @@ class BluetoothManagerService { } else if (state != STATE_ON && state != STATE_OFF && state != STATE_BLE_ON) { // Bluetooth is turning state return ADD_PROXY_DELAY_MS; - } else if (mHandler.hasMessages(MESSAGE_ENABLE) - || mHandler.hasMessages(MESSAGE_DISABLE) + } else if ((!Flags.systemServerRemoveExtraThreadJump() + && (mHandler.hasMessages(MESSAGE_ENABLE) + || mHandler.hasMessages(MESSAGE_DISABLE))) || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED) || mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mHandler.hasMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE) @@ -1038,6 +1044,42 @@ class BluetoothManagerService { return true; } + private static CompletableFuture<Void> createDeathNotifier(IBinder binder) { + CompletableFuture<Void> deathNotifier = new CompletableFuture<>(); + try { + binder.linkToDeath( + () -> { + Log.i(TAG, "Successfully received Bluetooth death"); + deathNotifier.complete(null); + }, + 0); + } catch (RemoteException e) { + Log.e(TAG, "listenBinderDeath(): Failed to linkToDeath", e); + deathNotifier.complete(null); + } + return deathNotifier; + } + + private static void killBluetoothProcess( + AdapterBinder adapter, CompletableFuture<Void> deathNotifier) { + try { + // Force kill Bluetooth to make sure its process is not reused. + // Note: In a perfect world, we should be able to re-init the same process. + // Unfortunately, this requires an heavy rework of the Bluetooth app + // TODO: b/339501753 - Properly stop Bluetooth without killing it + adapter.killBluetoothProcess(); + + deathNotifier.get(2_000, TimeUnit.MILLISECONDS); + } catch (android.os.DeadObjectException e) { + // Reduce exception to info and skip waiting (Bluetooth is dead as wanted) + Log.i(TAG, "killBluetoothProcess(): Bluetooth already dead 💀"); + } catch (RemoteException e) { + Log.e(TAG, "killBluetoothProcess(): Unable to call killBluetoothProcess", e); + } catch (TimeoutException | InterruptedException | ExecutionException e) { + Log.e(TAG, "killBluetoothProcess(): Bluetooth death not received after > 2000ms", e); + } + } + void unbindAndFinish() { Log.d(TAG, "unbindAndFinish(): mAdapter=" + mAdapter + " isBinding=" + isBinding()); @@ -1054,40 +1096,13 @@ class BluetoothManagerService { Log.e(TAG, "unbindAndFinish(): Unable to unregister BluetoothCallback", e); } - CompletableFuture<Void> binderDead = new CompletableFuture<>(); - try { - mAdapter.getAdapterBinder() - .asBinder() - .linkToDeath( - () -> { - Log.i(TAG, "Successfully received Bluetooth death"); - binderDead.complete(null); - }, - 0); - } catch (RemoteException e) { - Log.e(TAG, "unbindAndFinish(): Failed to linkToDeath", e); - binderDead.complete(null); - } + CompletableFuture<Void> deathNotifier = + createDeathNotifier(mAdapter.getAdapterBinder().asBinder()); // Unbind first to avoid receiving unwanted "onServiceDisconnected" mContext.unbindService(mConnection); - try { - // Force kill Bluetooth to make sure its process is not reused. - // Note: In a perfect world, we should be able to re-init the same process. - // Unfortunately, this requires an heavy rework of the Bluetooth app - // TODO: b/339501753 - Properly stop Bluetooth without killing it - mAdapter.killBluetoothProcess(); - - binderDead.get(2_000, TimeUnit.MILLISECONDS); - } catch (android.os.DeadObjectException e) { - // Reduce exception to info and skip waiting (Bluetooth is dead as wanted) - Log.i(TAG, "unbindAndFinish(): Bluetooth already dead 💀"); - } catch (RemoteException e) { - Log.e(TAG, "unbindAndFinish(): Unable to call killBluetoothProcess", e); - } catch (TimeoutException | InterruptedException | ExecutionException e) { - Log.e(TAG, "unbindAndFinish(): Bluetooth death not received after > 2000ms", e); - } + killBluetoothProcess(mAdapter, deathNotifier); long timeSpentForShutdown = System.currentTimeMillis() - currentTimeMs; mShutdownLatencyHistogram.logSample((float) timeSpentForShutdown); @@ -1228,10 +1243,10 @@ class BluetoothManagerService { } if (Flags.setComponentAvailableFix()) { - mHandler - .obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED, - componentName.getPackageName()) - .sendToTarget(); + mHandler.obtainMessage( + MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED, + componentName.getPackageName()) + .sendToTarget(); } else { mHandler.sendEmptyMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); } @@ -1252,8 +1267,12 @@ class BluetoothManagerService { public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_ENABLE: - int quietEnable = msg.arg1; - int isBle = msg.arg2; + if (Flags.systemServerRemoveExtraThreadJump()) { + break; + } + + boolean quietEnable = msg.arg1 != 0; + boolean isBle = msg.arg2 != 0; Log.d( TAG, @@ -1265,6 +1284,10 @@ class BluetoothManagerService { break; case MESSAGE_DISABLE: + if (Flags.systemServerRemoveExtraThreadJump()) { + break; + } + Log.d(TAG, "MESSAGE_DISABLE: mAdapter=" + mAdapter); handleDisableMessage(); @@ -1311,6 +1334,15 @@ class BluetoothManagerService { case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: IBinder service = (IBinder) msg.obj; + + // Handle case where disable was called before binding complete. + if (Flags.systemServerRemoveExtraThreadJump() && !isBinding() && !mEnable) { + Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: after cancelling binding"); + AdapterBinder adapter = + BluetoothServerProxy.getInstance().createAdapterBinder(service); + killBluetoothProcess(adapter, createDeathNotifier(service)); + break; + } Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: service=" + service); // Remove timeout @@ -1330,7 +1362,7 @@ class BluetoothManagerService { offToBleOn(); sendBluetoothServiceUpCallback(); - if (!mEnable) { + if (!Flags.systemServerRemoveExtraThreadJump() && !mEnable) { waitForState(STATE_ON); onToBleOn(); } @@ -1359,13 +1391,31 @@ class BluetoothManagerService { } // If we tried to enable BT while BT was in the process of shutting down, // wait for the BT process to fully tear down and then force a restart - // here. This is a bit of a hack (b/29363429). + // here. This is a bit of a hack (b/29363429). if (prevState == STATE_BLE_TURNING_OFF && newState == STATE_OFF) { - if (mEnable) { - Log.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting."); - waitForState(STATE_OFF); - mHandler.sendEmptyMessageDelayed( - MESSAGE_RESTART_BLUETOOTH_SERVICE, getServiceRestartMs()); + if (Flags.enableBleWhileDisablingAirplane()) { + if (mHandler.hasMessages(0, ON_AIRPLANE_MODE_CHANGED_TOKEN)) { + mHandler.removeCallbacksAndMessages(ON_AIRPLANE_MODE_CHANGED_TOKEN); + Log.d(TAG, "Handling delayed airplane mode event"); + handleAirplaneModeChanged(AirplaneModeListener.isOnOverrode()); + } + if (mEnable && !isBinding()) { + Log.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting."); + if (!Flags.systemServerRemoveExtraThreadJump()) { + waitForState(STATE_OFF); + } + mHandler.sendEmptyMessageDelayed( + MESSAGE_RESTART_BLUETOOTH_SERVICE, getServiceRestartMs()); + } + } else { + if (mEnable) { + Log.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting."); + if (!Flags.systemServerRemoveExtraThreadJump()) { + waitForState(STATE_OFF); + } + mHandler.sendEmptyMessageDelayed( + MESSAGE_RESTART_BLUETOOTH_SERVICE, getServiceRestartMs()); + } } } if (newState == STATE_ON || newState == STATE_BLE_ON) { @@ -1524,17 +1574,19 @@ class BluetoothManagerService { return mHandler.hasMessages(MESSAGE_TIMEOUT_BIND); } - private void handleEnableMessage(int quietEnable, int isBle) { + private void handleEnableMessage(boolean quietEnable, boolean isBle) { + String logHeader = "handleEnableMessage(" + quietEnable + ", " + isBle + "): "; if (mShutdownInProgress) { - Log.d(TAG, "Skip Bluetooth Enable in device shutdown process"); + Log.d(TAG, logHeader + "Skip Bluetooth Enable in device shutdown process"); return; } - if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) - || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) { + if (!Flags.systemServerRemoveExtraThreadJump() + && (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) + || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED))) { // We are handling enable or disable right now, wait for it. mHandler.sendMessageDelayed( - mHandler.obtainMessage(MESSAGE_ENABLE, quietEnable, isBle), + mHandler.obtainMessage(MESSAGE_ENABLE, quietEnable ? 1 : 0, isBle ? 1 : 0), ENABLE_DISABLE_DELAY_MS); return; } @@ -1542,27 +1594,27 @@ class BluetoothManagerService { mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); mEnable = true; - if (isBle == 0) { + if (!isBle) { setBluetoothPersistedState(BLUETOOTH_ON_BLUETOOTH); } if (mState.oneOf(STATE_BLE_TURNING_ON, STATE_TURNING_ON, STATE_ON)) { - Log.i(TAG, "MESSAGE_ENABLE: already enabled. Current state=" + mState); + Log.i(TAG, logHeader + "Already enabled. Current state=" + mState); return; } - if (mState.oneOf(STATE_BLE_ON) && isBle == 1) { - Log.i(TAG, "MESSAGE_ENABLE: Already in BLE_ON while being requested to go to BLE_ON"); + if (mState.oneOf(STATE_BLE_ON) && isBle) { + Log.i(TAG, logHeader + "Already in BLE_ON while being requested to go to BLE_ON"); return; } if (mState.oneOf(STATE_BLE_ON)) { - Log.i(TAG, "MESSAGE_ENABLE: Bluetooth transition from STATE_BLE_ON to STATE_ON"); + Log.i(TAG, logHeader + "Bluetooth transition from STATE_BLE_ON to STATE_ON"); bleOnToOn(); return; } - if (mAdapter != null) { + if (!Flags.systemServerRemoveExtraThreadJump() && mAdapter != null) { // TODO: b/339548431 - Adapt this after removal of Flags.explicitKillFromSystemServer // // We need to wait until transitioned to STATE_OFF and the previous Bluetooth process @@ -1581,14 +1633,15 @@ class BluetoothManagerService { return; } - mQuietEnable = (quietEnable == 1); + mQuietEnable = quietEnable; handleEnable(); } private void handleDisableMessage() { - if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) - || isBinding() - || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) { + if (!Flags.systemServerRemoveExtraThreadJump() + && (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) + || isBinding() + || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED))) { // We are handling enable or disable right now, wait for it. mHandler.sendEmptyMessageDelayed(MESSAGE_DISABLE, ENABLE_DISABLE_DELAY_MS); return; @@ -1596,10 +1649,25 @@ class BluetoothManagerService { mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); - if (mEnable && mAdapter != null) { + if (Flags.systemServerRemoveExtraThreadJump() && isBinding()) { + Log.d(TAG, "Disable while binding"); + mEnable = false; + mContext.unbindService(mConnection); + mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); + mHandler.removeMessages(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); + } else if (Flags.systemServerRemoveExtraThreadJump() + && mState.oneOf(STATE_BLE_TURNING_ON)) { + Log.d(TAG, "Disable while BLE_TURNING_ON"); + mEnable = false; + bluetoothStateChangeHandler(STATE_BLE_TURNING_ON, STATE_OFF); + } else if (mEnable && mAdapter != null) { mWaitForDisableRetry = 0; - mHandler.sendEmptyMessageDelayed( - MESSAGE_HANDLE_DISABLE_DELAYED, ENABLE_DISABLE_DELAY_MS); + if (Flags.systemServerRemoveExtraThreadJump()) { + handleDisableDelayed(false); + } else { + mHandler.sendEmptyMessageDelayed( + MESSAGE_HANDLE_DISABLE_DELAYED, ENABLE_DISABLE_DELAY_MS); + } } else { mEnable = false; onToBleOn(); @@ -1648,6 +1716,10 @@ class BluetoothManagerService { Log.e(TAG, "Wait for STATE_OFF timeout"); } } + if (Flags.systemServerRemoveExtraThreadJump()) { + handleEnable(); + return; + } // Either state is changed to STATE_OFF or reaches the maximum retry, we // should move forward to the next step. mWaitForEnableRetry = 0; @@ -1656,6 +1728,9 @@ class BluetoothManagerService { } private void handleDisableDelayed(boolean disabling) { + if (Flags.systemServerRemoveExtraThreadJump() && disabling) { + return; + } if (!disabling) { // The Bluetooth is turning on, wait for STATE_ON if (!mState.oneOf(STATE_ON)) { @@ -1673,10 +1748,12 @@ class BluetoothManagerService { mWaitForDisableRetry = 0; mEnable = false; onToBleOn(); - // Wait for state exiting STATE_ON - Message disableDelayedMsg = - mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0); - mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS); + if (!Flags.systemServerRemoveExtraThreadJump()) { + // Wait for state exiting STATE_ON + Message disableDelayedMsg = + mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0); + mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS); + } } else { // The Bluetooth is turning off, wait for exiting STATE_ON if (mState.oneOf(STATE_ON)) { @@ -1837,8 +1914,13 @@ class BluetoothManagerService { } private void sendDisableMsg(int reason, String packageName) { - mHandler.sendEmptyMessage(MESSAGE_DISABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + mHandler.sendEmptyMessage(MESSAGE_DISABLE); + } ActiveLogs.add(reason, false, packageName, false); + if (Flags.systemServerRemoveExtraThreadJump()) { + handleDisableMessage(); + } } private void sendEnableMsg(boolean quietMode, int reason) { @@ -1850,9 +1932,14 @@ class BluetoothManagerService { } private void sendEnableMsg(boolean quietMode, int reason, String packageName, boolean isBle) { - mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, isBle ? 1 : 0).sendToTarget(); + if (!Flags.systemServerRemoveExtraThreadJump()) { + mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, isBle ? 1 : 0).sendToTarget(); + } ActiveLogs.add(reason, true, packageName, isBle); mLastEnabledTime = SystemClock.elapsedRealtime(); + if (Flags.systemServerRemoveExtraThreadJump()) { + handleEnableMessage(quietMode, isBle); + } } private void addCrashLog() { @@ -2254,33 +2341,34 @@ class BluetoothManagerService { } /** - * In case of a Bluetooth crash, mark it's enabled components as non longer available to - * trigger the PACKAGE_CHANGED intent. This should not be needed in a normal shutdown as the - * Bluetooth clean its components on its own + * In case of a Bluetooth crash, mark it's enabled components as non longer available to trigger + * the PACKAGE_CHANGED intent. This should not be needed in a normal shutdown as the Bluetooth + * clean its components on its own */ private void disableBluetoothComponents(String packageName) { PackageManager pm = mContext.getPackageManager(); PackageInfo packageInfo = null; try { - packageInfo = pm.getPackageInfo( - packageName, - PackageManager.GET_SERVICES | - PackageManager.GET_ACTIVITIES | - PackageManager.GET_RECEIVERS | - PackageManager.GET_PROVIDERS); + packageInfo = + pm.getPackageInfo( + packageName, + PackageManager.GET_SERVICES + | PackageManager.GET_ACTIVITIES + | PackageManager.GET_RECEIVERS + | PackageManager.GET_PROVIDERS); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Package not found: " + packageName, e); return; } // Refer to updateOppLauncherComponentState() - List<String> baseBluetoothOppActivities = List.of( - "com.android.bluetooth.opp.BluetoothOppLauncherActivity", - "com.android.bluetooth.opp.BluetoothOppBtEnableActivity", - "com.android.bluetooth.opp.BluetoothOppBtEnablingActivity", - "com.android.bluetooth.opp.BluetoothOppBtErrorActivity" - ); + List<String> baseBluetoothOppActivities = + List.of( + "com.android.bluetooth.opp.BluetoothOppLauncherActivity", + "com.android.bluetooth.opp.BluetoothOppBtEnableActivity", + "com.android.bluetooth.opp.BluetoothOppBtEnablingActivity", + "com.android.bluetooth.opp.BluetoothOppBtErrorActivity"); disableComponents(pm, packageInfo.activities, packageName, baseBluetoothOppActivities); disableComponents(pm, packageInfo.services, packageName, null); @@ -2295,17 +2383,20 @@ class BluetoothManagerService { } Arrays.stream(components) - .filter(componentInfo -> !componentInfo.enabled) - .map(componentInfo -> new ComponentName(packageName, componentInfo.name)) - .filter(componentName -> - (componentsToKeep == null || - !componentsToKeep.contains(componentName.getClassName()))) - .forEach(componentName -> { - pm.setComponentEnabledSetting( - componentName, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - Log.i(TAG, "Disabled component: " + componentName.flattenToString()); - }); + .filter(componentInfo -> !componentInfo.enabled) + .map(componentInfo -> new ComponentName(packageName, componentInfo.name)) + .filter( + componentName -> + (componentsToKeep == null + || !componentsToKeep.contains( + componentName.getClassName()))) + .forEach( + componentName -> { + pm.setComponentEnabledSetting( + componentName, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + Log.i(TAG, "Disabled component: " + componentName.flattenToString()); + }); } } diff --git a/service/tests/Android.bp b/service/tests/Android.bp index 217bd36f70..8bdefcc8ac 100644 --- a/service/tests/Android.bp +++ b/service/tests/Android.bp @@ -26,6 +26,7 @@ android_test { ], static_libs: [ + "androidx.test.espresso.intents", "androidx.test.rules", "flag-junit", "frameworks-base-testutils", diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java index 480af98329..e825940e90 100644 --- a/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java +++ b/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java @@ -22,6 +22,9 @@ import static android.bluetooth.BluetoothAdapter.STATE_ON; import static android.bluetooth.BluetoothAdapter.STATE_TURNING_OFF; import static android.bluetooth.BluetoothAdapter.STATE_TURNING_ON; +import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction; +import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra; + import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_SERVICE_CONNECTED; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_STATE_CHANGE; @@ -33,6 +36,7 @@ import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_RESTO import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_TIMEOUT_BIND; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; @@ -41,13 +45,16 @@ import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.validateMockitoUsage; import static org.mockito.Mockito.verify; import android.annotation.SuppressLint; +import android.app.AppOpsManager; import android.app.PropertyInvalidatedCache; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothManager; @@ -55,7 +62,6 @@ import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothStateChangeCallback; import android.content.ComponentName; import android.content.Context; -import android.content.ContextWrapper; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; @@ -63,21 +69,29 @@ import android.os.Message; import android.os.UserHandle; import android.os.UserManager; import android.os.test.TestLooper; +import android.permission.PermissionManager; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.FlagsParameterization; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.bluetooth.flags.Flags; + +import org.hamcrest.Matcher; +import org.hamcrest.core.AllOf; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.Spy; +import org.mockito.hamcrest.MockitoHamcrest; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; @@ -93,7 +107,8 @@ public class BluetoothManagerServiceTest { @Parameters(name = "{0}") public static List<FlagsParameterization> getParams() { - return FlagsParameterization.allCombinationsOf(); + return FlagsParameterization.allCombinationsOf( + Flags.FLAG_SYSTEM_SERVER_REMOVE_EXTRA_THREAD_JUMP); } public BluetoothManagerServiceTest(FlagsParameterization flags) { @@ -103,24 +118,26 @@ public class BluetoothManagerServiceTest { private static final int STATE_BLE_TURNING_ON = 14; // can't find the symbol because hidden api private static final int STATE_BLE_TURNING_OFF = 16; // can't find the symbol because hidden api - BluetoothManagerService mManagerService; + private final Context mTargetContext = + InstrumentationRegistry.getInstrumentation().getTargetContext(); - @Spy - private final Context mContext = - new ContextWrapper(InstrumentationRegistry.getInstrumentation().getTargetContext()); - - @Spy BluetoothServerProxy mBluetoothServerProxy; + @Mock BluetoothServerProxy mBluetoothServerProxy; + @Mock Context mContext; @Mock UserManager mUserManager; @Mock UserHandle mUserHandle; - @Mock IBinder mBinder; @Mock IBluetoothManagerCallback mManagerCallback; @Mock IBluetoothStateChangeCallback mStateChangeCallback; - @Mock IBluetooth mAdapterService; @Mock AdapterBinder mAdapterBinder; + @Mock AppOpsManager mAppOpsManager; + @Mock PermissionManager mPermissionManager; + + private int mPersistedState = BluetoothManagerService.BLUETOOTH_OFF; - TestLooper mLooper; + private InOrder mInOrder; + private TestLooper mLooper; + private BluetoothManagerService mManagerService; private static class ServerQuery extends PropertyInvalidatedCache.QueryHandler<IBluetoothManager, Integer> { @@ -146,6 +163,7 @@ public class BluetoothManagerServiceTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mInOrder = inOrder(mContext, mManagerCallback, mAdapterBinder); PropertyInvalidatedCache<IBluetoothManager, Integer> testCache = new PropertyInvalidatedCache<>( @@ -163,24 +181,37 @@ public class BluetoothManagerServiceTest { doReturn("00:11:22:33:44:55") .when(mBluetoothServerProxy) .settingsSecureGetString(any(), eq(Settings.Secure.BLUETOOTH_ADDRESS)); - // Set persisted state to BLUETOOTH_OFF to not generate unwanted behavior when starting test - doReturn(BluetoothManagerService.BLUETOOTH_OFF) + doAnswer( + inv -> { + return mPersistedState; + }) .when(mBluetoothServerProxy) .getBluetoothPersistedState(any(), anyInt()); doAnswer( inv -> { - doReturn(inv.getArguments()[1]) - .when(mBluetoothServerProxy) - .getBluetoothPersistedState(any(), anyInt()); + mPersistedState = inv.getArgument(1); return null; }) .when(mBluetoothServerProxy) .setBluetoothPersistedState(any(), anyInt()); - // Test is not allowed to send broadcast as Bluetooth. doNothing Prevent SecurityException - doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any(), any()); + doAnswer( + inv -> { + IBinder.DeathRecipient recipient = inv.getArgument(0); + recipient.binderDied(); + return null; + }) + .when(mBinder) + .linkToDeath(any(), anyInt()); + + doReturn(BluetoothManagerServiceTest.class.getSimpleName()).when(mContext).getPackageName(); + doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt()); + doReturn(mTargetContext.getContentResolver()).when(mContext).getContentResolver(); + doReturn(mTargetContext.getPackageManager()).when(mContext).getPackageManager(); doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class); + doReturn(mPermissionManager).when(mContext).getSystemService(PermissionManager.class); doReturn(mBinder).when(mManagerCallback).asBinder(); @@ -233,9 +264,13 @@ public class BluetoothManagerServiceTest { IntStream.of(what) .forEach( w -> { + String log = "Expecting message " + w + ": "; + Message msg = mLooper.nextMessage(); - assertThat(msg).isNotNull(); - assertThat(msg.what).isEqualTo(w); + assertWithMessage(log + "but got null").that(msg).isNotNull(); + assertWithMessage(log + "but got " + msg.what) + .that(msg.what) + .isEqualTo(w); msg.getTarget().dispatchMessage(msg); }); } @@ -270,7 +305,9 @@ public class BluetoothManagerServiceTest { // called from SYSTEM user, should try to toggle Bluetooth off mManagerService.onUserRestrictionsChanged(UserHandle.SYSTEM); - syncHandler(MESSAGE_DISABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_DISABLE); + } } @Test @@ -283,8 +320,11 @@ public class BluetoothManagerServiceTest { anyInt(), any(UserHandle.class)); mManagerService.enableBle("enable_bindFailure_removesTimeout", mBinder); - syncHandler(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_ENABLE); + } verify(mContext).unbindService(any()); + mInOrder.verify(mContext).unbindService(any()); // TODO(b/280518177): Failed to start should be noted / reported in metrics // Maybe show a popup or a crash notification @@ -294,7 +334,9 @@ public class BluetoothManagerServiceTest { @Test public void enable_bindTimeout() throws Exception { mManagerService.enableBle("enable_bindTimeout", mBinder); - syncHandler(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_ENABLE); + } mLooper.moveTimeForward(120_000); // 120 seconds syncHandler(MESSAGE_TIMEOUT_BIND); @@ -312,7 +354,7 @@ public class BluetoothManagerServiceTest { ArgumentCaptor<BluetoothManagerService.BluetoothServiceConnection> captor = ArgumentCaptor.forClass(BluetoothManagerService.BluetoothServiceConnection.class); - verify(mContext) + mInOrder.verify(mContext) .bindServiceAsUser( any(Intent.class), captor.capture(), anyInt(), any(UserHandle.class)); assertThat(captor.getAllValues()).hasSize(1); @@ -324,11 +366,10 @@ public class BluetoothManagerServiceTest { return serviceConnection; } - private static IBluetoothCallback captureBluetoothCallback(AdapterBinder adapterBinder) - throws Exception { + private IBluetoothCallback captureBluetoothCallback() throws Exception { ArgumentCaptor<IBluetoothCallback> captor = ArgumentCaptor.forClass(IBluetoothCallback.class); - verify(adapterBinder).registerCallback(captor.capture(), any()); + mInOrder.verify(mAdapterBinder).registerCallback(captor.capture(), any()); assertThat(captor.getAllValues()).hasSize(1); return captor.getValue(); } @@ -337,11 +378,10 @@ public class BluetoothManagerServiceTest { // Binding of IBluetooth acceptBluetoothBinding(); - // TODO(b/280518177): This callback is too early, bt is not ON nor BLE_ON - verify(mManagerCallback).onBluetoothServiceUp(any()); - - IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder); - verify(mAdapterBinder).offToBleOn(anyBoolean(), any()); + IBluetoothCallback btCallback = captureBluetoothCallback(); + mInOrder.verify(mAdapterBinder).offToBleOn(anyBoolean(), any()); + verifyBleStateIntentSent(STATE_OFF, STATE_BLE_TURNING_ON); + mInOrder.verify(mManagerCallback).onBluetoothServiceUp(any()); assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON); @@ -349,30 +389,30 @@ public class BluetoothManagerServiceTest { // trigger the stateChangeCallback from native btCallback.onBluetoothStateChange(STATE_BLE_TURNING_ON, STATE_BLE_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); + verifyBleStateIntentSent(STATE_BLE_TURNING_ON, STATE_BLE_ON); return btCallback; } private IBluetoothCallback transition_offToOn() throws Exception { IBluetoothCallback btCallback = transition_offToBleOn(); - verify(mAdapterBinder).bleOnToOn(any()); + mInOrder.verify(mAdapterBinder).bleOnToOn(any()); // AdapterService go to turning_on and start all profile on its own btCallback.onBluetoothStateChange(STATE_BLE_ON, STATE_TURNING_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); + verifyBleStateIntentSent(STATE_BLE_ON, STATE_TURNING_ON); + verifyStateIntentSent(STATE_OFF, STATE_TURNING_ON); // When all the profile are started, adapterService consider it is ON btCallback.onBluetoothStateChange(STATE_TURNING_ON, STATE_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); - - // Check that we sent 6 intent, 4 for BLE: BLE_TURNING_ON + BLE_ON + TURNING_ON + ON - // and 2 for classic: TURNING_ON + ON - // TODO(b/280518177): assert the intent are the correct one - verify(mContext, times(6)).sendBroadcastAsUser(any(), any(), any(), any()); + verifyBleStateIntentSent(STATE_TURNING_ON, STATE_ON); + verifyStateIntentSent(STATE_TURNING_ON, STATE_ON); return btCallback; } private void transition_onToBleOn(IBluetoothCallback btCallback) throws Exception { - verify(mAdapterBinder).onToBleOn(any()); + mInOrder.verify(mAdapterBinder).onToBleOn(any()); btCallback.onBluetoothStateChange(STATE_TURNING_OFF, STATE_BLE_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); @@ -380,7 +420,7 @@ public class BluetoothManagerServiceTest { private void transition_onToOff(IBluetoothCallback btCallback) throws Exception { transition_onToBleOn(btCallback); - verify(mAdapterBinder).bleOnToOff(any()); + mInOrder.verify(mAdapterBinder).bleOnToOff(any()); // When all the profile are started, adapterService consider it is ON btCallback.onBluetoothStateChange(STATE_BLE_TURNING_OFF, STATE_OFF); @@ -390,62 +430,70 @@ public class BluetoothManagerServiceTest { @Test public void enable_whileTurningToBleOn_shouldEnable() throws Exception { mManagerService.enableBle("enable_whileTurningToBleOn_shouldEnable", mBinder); - syncHandler(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_ENABLE); + } acceptBluetoothBinding(); - IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder); + IBluetoothCallback btCallback = captureBluetoothCallback(); assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON); // receive enable when Bluetooth is in BLE_TURNING_ON mManagerService.enable("enable_whileTurningToBleOn_shouldEnable"); - syncHandler(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_ENABLE); + } btCallback.onBluetoothStateChange(STATE_BLE_TURNING_ON, STATE_BLE_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); - verify(mAdapterBinder).bleOnToOn(any()); + mInOrder.verify(mAdapterBinder).bleOnToOn(any()); } @Test public void enable_whileNotYetBoundToBle_shouldEnable() throws Exception { mManagerService.enableBle("enable_whileTurningToBleOn_shouldEnable", mBinder); - syncHandler(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_ENABLE); + } assertThat(mManagerService.getState()).isEqualTo(STATE_OFF); // receive enable when Bluetooth is OFF and not yet binded mManagerService.enable("enable_whileTurningToBleOn_shouldEnable"); - syncHandler(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_ENABLE); + } acceptBluetoothBinding(); - IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder); + IBluetoothCallback btCallback = captureBluetoothCallback(); assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON); btCallback.onBluetoothStateChange(STATE_BLE_TURNING_ON, STATE_BLE_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); - verify(mAdapterBinder).bleOnToOn(any()); + mInOrder.verify(mAdapterBinder).bleOnToOn(any()); } @Test public void offToBleOn() throws Exception { mManagerService.enableBle("test_offToBleOn", mBinder); - syncHandler(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_ENABLE); + } transition_offToBleOn(); - // Check that we sent 2 intent, one for BLE_TURNING_ON, one for BLE_ON - // TODO(b/280518177): assert the intent are the correct one - verify(mContext, times(2)).sendBroadcastAsUser(any(), any(), any(), any()); - // Check that there was no transition to STATE_ON - verify(mAdapterBinder, times(0)).bleOnToOn(any()); + mInOrder.verify(mAdapterBinder, never()).bleOnToOn(any()); assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_ON); } @Test public void offToOn() throws Exception { mManagerService.enable("test_offToOn"); - syncHandler(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_ENABLE); + } transition_offToOn(); @@ -455,13 +503,15 @@ public class BluetoothManagerServiceTest { @Test public void crash_whileTransitionState_canRecover() throws Exception { mManagerService.enableBle("crash_whileTransitionState_canRecover", mBinder); - syncHandler(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_ENABLE); + } BluetoothManagerService.BluetoothServiceConnection serviceConnection = acceptBluetoothBinding(); - IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder); - verify(mAdapterBinder).offToBleOn(anyBoolean(), any()); + IBluetoothCallback btCallback = captureBluetoothCallback(); + mInOrder.verify(mAdapterBinder).offToBleOn(anyBoolean(), any()); btCallback.onBluetoothStateChange(STATE_OFF, STATE_BLE_TURNING_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON); @@ -484,42 +534,136 @@ public class BluetoothManagerServiceTest { @Test public void disableAirplane_whenNothing_startBluetooth() throws Exception { - doReturn(BluetoothManagerService.BLUETOOTH_ON_BLUETOOTH) - .when(mBluetoothServerProxy) - .getBluetoothPersistedState(any(), anyInt()); + if (!Flags.systemServerRemoveExtraThreadJump()) { + mPersistedState = BluetoothManagerService.BLUETOOTH_ON_BLUETOOTH; + } mManagerService.enable("disableAirplane_whenNothing_startBluetooth"); - discardMessage(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + discardMessage(MESSAGE_ENABLE); + } else { + transition_offToOn(); + } + + assertThat(mLooper.nextMessage()).isNull(); mManagerService.onAirplaneModeChanged(false); - discardMessage(MESSAGE_ENABLE); + if (!Flags.systemServerRemoveExtraThreadJump()) { + discardMessage(MESSAGE_ENABLE); + } } @Test - public void disableAirplane_whenFactoryReset_doesNotStartBluetooth() throws Exception { - doAnswer( - invocation -> { - IBinder.DeathRecipient recipient = invocation.getArgument(0); - recipient.binderDied(); - return null; - }) - .when(mBinder) - .linkToDeath(any(), anyInt()); + @EnableFlags(Flags.FLAG_SYSTEM_SERVER_REMOVE_EXTRA_THREAD_JUMP) + public void disable_whenBinding_bluetoothShouldStop_new() throws Exception { + mManagerService.enable("disable_whenBinding_bluetoothShouldStop_new"); + mInOrder.verify(mContext).bindServiceAsUser(any(), any(), anyInt(), any()); + mManagerService.disable("disable_whenBinding_bluetoothShouldStop_new", true); + mInOrder.verify(mContext).unbindService(any()); + assertThat(mManagerService.getState()).isEqualTo(STATE_OFF); + } - mManagerService.enable("test_offToOn"); + @Test + @EnableFlags(Flags.FLAG_SYSTEM_SERVER_REMOVE_EXTRA_THREAD_JUMP) + public void disable_whenTurningBleOn_bluetoothShouldStop() throws Exception { + mManagerService.enable("disable_whenBinding_bluetoothShouldStop_new"); + acceptBluetoothBinding(); + assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON); + mManagerService.disable("disable_whenBinding_bluetoothShouldStop_new", true); + mInOrder.verify(mContext).unbindService(any()); + assertThat(mManagerService.getState()).isEqualTo(STATE_OFF); + } + + @Test + @DisableFlags(Flags.FLAG_SYSTEM_SERVER_REMOVE_EXTRA_THREAD_JUMP) + public void disable_whenBinding_bluetoothShouldStop_old() throws Exception { + mManagerService.enable("disable_whenBinding_bluetoothShouldStop_old"); syncHandler(MESSAGE_ENABLE); + mManagerService.disable("disable_whenBinding_bluetoothShouldStop_old", true); + syncHandler(MESSAGE_DISABLE); + + IBluetoothCallback btCallback = transition_offToBleOn(); + assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_OFF); + + btCallback.onBluetoothStateChange(STATE_BLE_TURNING_OFF, STATE_OFF); + syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); + + mLooper.moveTimeForward(BluetoothManagerService.ENABLE_DISABLE_DELAY_MS); + syncHandler(MESSAGE_DISABLE); + + assertThat(mManagerService.getState()).isEqualTo(STATE_OFF); + } + + @Test + public void disableAirplane_whenFactoryReset_doesNotStartBluetooth() throws Exception { + mManagerService.enable("disableAirplane_whenFactoryReset_doesNotStartBluetooth"); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_ENABLE); + } IBluetoothCallback btCallback = transition_offToOn(); assertThat(mManagerService.getState()).isEqualTo(STATE_ON); mManagerService.mHandler.sendEmptyMessage(MESSAGE_RESTORE_USER_SETTING_OFF); syncHandler(MESSAGE_RESTORE_USER_SETTING_OFF); - syncHandler(MESSAGE_DISABLE); - mLooper.moveTimeForward(BluetoothManagerService.ENABLE_DISABLE_DELAY_MS); - syncHandler(MESSAGE_HANDLE_DISABLE_DELAYED); - mLooper.moveTimeForward(BluetoothManagerService.ENABLE_DISABLE_DELAY_MS); - syncHandler(MESSAGE_HANDLE_DISABLE_DELAYED); + if (!Flags.systemServerRemoveExtraThreadJump()) { + syncHandler(MESSAGE_DISABLE); + mLooper.moveTimeForward(BluetoothManagerService.ENABLE_DISABLE_DELAY_MS); + syncHandler(MESSAGE_HANDLE_DISABLE_DELAYED); + mLooper.moveTimeForward(BluetoothManagerService.ENABLE_DISABLE_DELAY_MS); + syncHandler(MESSAGE_HANDLE_DISABLE_DELAYED); + } transition_onToOff(btCallback); mManagerService.onAirplaneModeChanged(false); assertThat(mLooper.nextMessage()).isNull(); // Must not create a MESSAGE_ENABLE } + + @Test + @EnableFlags({ + Flags.FLAG_SYSTEM_SERVER_REMOVE_EXTRA_THREAD_JUMP, + Flags.FLAG_ENABLE_BLE_WHILE_DISABLING_AIRPLANE + }) + public void enableBle_whenDisableAirplaneIsDelayed_startBluetooth() throws Exception { + mManagerService.enable("enableBle_whenDisableAirplaneIsDelayed_startBluetooth"); + IBluetoothCallback btCallback = transition_offToOn(); + mManagerService.onAirplaneModeChanged(true); + assertThat(mManagerService.getState()).isEqualTo(STATE_TURNING_OFF); + + // Generate an event that will be delayed due to the TURNING_OFF state + mManagerService.onAirplaneModeChanged(false); + + transition_onToBleOn(btCallback); + mInOrder.verify(mAdapterBinder).bleOnToOff(any()); + assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_OFF); + + // As soon as we left BLE_ON, generate a call from 3p app that request to turn on Bluetooth + mManagerService.enableBle("enableBle_whenDisableAirplaneIsDelayed_startBluetooth", mBinder); + + // When all the profile are started, adapterService consider it is ON + btCallback.onBluetoothStateChange(STATE_BLE_TURNING_OFF, STATE_OFF); + syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); + + transition_offToOn(); + assertThat(mManagerService.getState()).isEqualTo(STATE_ON); + } + + @SafeVarargs + private void verifyIntentSent(Matcher<Intent>... matchers) { + mInOrder.verify(mContext) + .sendBroadcastAsUser( + MockitoHamcrest.argThat(AllOf.allOf(matchers)), any(), any(), any()); + } + + private void verifyBleStateIntentSent(int from, int to) { + verifyIntentSent( + hasAction(BluetoothAdapter.ACTION_BLE_STATE_CHANGED), + hasExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, from), + hasExtra(BluetoothAdapter.EXTRA_STATE, to)); + } + + private void verifyStateIntentSent(int from, int to) { + verifyIntentSent( + hasAction(BluetoothAdapter.ACTION_STATE_CHANGED), + hasExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, from), + hasExtra(BluetoothAdapter.EXTRA_STATE, to)); + } } diff --git a/sysprop/OWNERS b/sysprop/OWNERS deleted file mode 100644 index 5b3f4bad26..0000000000 --- a/sysprop/OWNERS +++ /dev/null @@ -1 +0,0 @@ -wescande@google.com diff --git a/system/BUILD.gn b/system/BUILD.gn index b86ca5f392..1d6325e6d9 100644 --- a/system/BUILD.gn +++ b/system/BUILD.gn @@ -41,7 +41,6 @@ group("bluetooth") { #if (use.test) { #group("bluetooth_tests") { #deps = [ - #"//bt/system/btcore:net_test_btcore", #"//bt/system/common:bluetooth_test_common", #"//bt/system/profile/avrcp:net_test_avrcp", #"//bt/system/service:bluetoothtbd_test", @@ -76,7 +75,6 @@ config("target_defaults") { "//bt/system", "//bt/flags/exported_include", "//bt/sysprop/exported_include", - "//bt/system/linux_include", "//bt/system/include", "//bt/system/gd", "//bt/system/pdl/hci/include", diff --git a/system/OWNERS b/system/OWNERS deleted file mode 100644 index b2acb91716..0000000000 --- a/system/OWNERS +++ /dev/null @@ -1,18 +0,0 @@ -# Reviewers for /system - -bhaktha@google.com -eruffieux@google.com -hallstrom@google.com -henrichataing@google.com -jpawlowski@google.com -okamil@google.com -poahlo@google.com -rongxuan@google.com -rwt@google.com -wescande@google.com - -# Reviewers for Channel Sounding related files -per-file /bta/ras/*=file:/OWNERS_channel_sounding -per-file /gd/hal/ranging_hal*=file:/OWNERS_channel_sounding -per-file /gd/hci/distance_measurement_*=file:/OWNERS_channel_sounding -per-file /main/shim/distance_measurement_manager*=file:/OWNERS_channel_sounding 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 be7cf3a6b2..e0b96475d3 100644 --- a/system/audio_hal_interface/aidl/le_audio_software_aidl.cc +++ b/system/audio_hal_interface/aidl/le_audio_software_aidl.cc @@ -30,6 +30,7 @@ #include "common/strings.h" #include "hal_version_manager.h" #include "le_audio_utils.h" +#include "osi/include/properties.h" namespace bluetooth { namespace audio { @@ -694,6 +695,14 @@ bluetooth::audio::le_audio::OffloadCapabilities get_offload_capabilities() { return {offload_capabilities, broadcast_offload_capabilities}; } +static bool IsUsingCodecExtensibility() { + auto codec_ext_status = + osi_property_get_bool("bluetooth.core.le_audio.codec_extension_aidl.enabled", false); + + log::debug("Using codec extensibility AIDL: {}", codec_ext_status); + return codec_ext_status; +} + AudioConfiguration stream_config_to_hal_audio_config( const ::bluetooth::le_audio::stream_config& offload_config) { LeAudioConfiguration ucast_config = { @@ -726,6 +735,7 @@ AudioConfiguration stream_config_to_hal_audio_config( .blocksPerSdu = static_cast<int8_t>(offload_config.codec_frames_blocks_per_sdu), }; ucast_config.leAudioCodecConfig = LeAudioCodecConfiguration(lc3_config); + ucast_config.codecType = CodecType::LC3; lc3_codec_config_found = true; } @@ -741,14 +751,20 @@ AudioConfiguration stream_config_to_hal_audio_config( BLE_ADDRESS_RANDOM; } - ucast_config.streamMap.push_back({ + LeAudioConfiguration::StreamMap map_entry = { .streamHandle = info.stream_handle, .audioChannelAllocation = static_cast<int32_t>(info.audio_channel_allocation), .isStreamActive = info.is_stream_active, - .aseConfiguration = GetAidlLeAudioAseConfigurationFromStackFormat( - info.codec_config, info.target_latency, info.target_phy, info.metadata), - .bluetoothDeviceAddress = aidl_device_address, - }); + }; + + // Add the additional codec extensibility data fields + if (IsUsingCodecExtensibility()) { + map_entry.aseConfiguration = GetAidlLeAudioAseConfigurationFromStackFormat( + info.codec_config, info.target_latency, info.target_phy, info.metadata); + map_entry.bluetoothDeviceAddress = aidl_device_address; + } + + ucast_config.streamMap.push_back(map_entry); } if (!lc3_codec_config_found) { diff --git a/system/bta/Android.bp b/system/bta/Android.bp index 52d34d59cc..22074caf65 100644 --- a/system/bta/Android.bp +++ b/system/bta/Android.bp @@ -231,6 +231,7 @@ cc_test { ":TestMockBtif", ":TestMockDevice", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackA2dp", ":TestMockStackAcl", @@ -243,7 +244,6 @@ cc_test { ":TestMockStackGatt", ":TestMockStackHid", ":TestMockStackL2cap", - ":TestMockStackMetrics", ":TestMockStackPan", ":TestMockStackRfcomm", ":TestMockStackRnr", @@ -339,10 +339,10 @@ cc_test { ":TestMockBtif", ":TestMockDevice", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackBtm", ":TestMockStackL2cap", - ":TestMockStackMetrics", "test/gatt/database_builder_sample_device_test.cc", "test/gatt/database_builder_test.cc", "test/gatt/database_test.cc", @@ -1347,6 +1347,74 @@ cc_test { } cc_test { + name: "bluetooth_hearing_aid_test", + test_suites: ["general-tests"], + defaults: [ + "fluoride_bta_defaults", + "mts_defaults", + ], + host_supported: true, + include_dirs: [ + "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/bta/include", + "packages/modules/Bluetooth/system/bta/test/common", + "packages/modules/Bluetooth/system/stack/include", + ], + srcs: [ + ":TestCommonMockFunctions", + ":TestMockBtaHearingAidAudioSource", + ":TestMockDevice", + ":TestMockMainShim", + ":TestMockMainShimEntry", + ":TestMockStackBtmInterface", + ":TestMockStackBtmIso", + ":TestMockStackGapConnInterface", + ":TestMockStackL2cap", + ":TestStubOsi", + "gatt/database.cc", + "gatt/database_builder.cc", + "hearing_aid/hearing_aid.cc", + "hearing_aid/hearing_aid_test.cc", + "test/common/bta_gatt_api_mock.cc", + "test/common/bta_gatt_queue_mock.cc", + "test/common/btif_storage_mock.cc", + "test/common/btm_api_mock.cc", + ], + shared_libs: [ + "libbase", + "libcrypto", + "liblog", + ], + static_libs: [ + "bluetooth_flags_c_lib_for_test", + "libaconfig_storage_read_api_cc", + "libbluetooth-types", + "libbluetooth_crypto_toolbox", + "libbluetooth_gd", + "libbluetooth_log", + "libbt-audio-asrc", + "libbt-btu-main-thread", + "libbt-common", + "libbt-platform-protos-lite", + "libchrome", + "libevent", + "libg722codec", + "libgmock", + "server_configurable_flags", + ], + sanitize: { + cfi: true, + scs: true, + address: true, + all_undefined: true, + integer_overflow: true, + diag: { + undefined: true, + }, + }, +} + +cc_test { name: "bluetooth_hh_test", test_suites: ["general-tests"], defaults: [ diff --git a/system/bta/BUILD.gn b/system/bta/BUILD.gn index 9c28016617..f621539151 100644 --- a/system/bta/BUILD.gn +++ b/system/bta/BUILD.gn @@ -143,7 +143,6 @@ static_library("bta") { "sys", "//bt/system/", "//bt/system/include", - "//bt/system/linux_include", "//bt/system/bta", "//bt/system/bta/aics/include", "//bt/system/gd", diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc index 48e0f16c99..ddc481171f 100644 --- a/system/bta/dm/bta_dm_act.cc +++ b/system/bta/dm/bta_dm_act.cc @@ -545,7 +545,7 @@ void bta_dm_remove_device(const RawAddress& target) { if (le_connected || bredr_connected) { // Wait for all transports to be disconnected - tBTA_DM_REMOVE_PENDNIG node = {pseudo_addr, identity_addr, le_connected, bredr_connected}; + tBTA_DM_REMOVE_PENDING node = {pseudo_addr, identity_addr, le_connected, bredr_connected}; bta_dm_cb.pending_removals.push_back(node); log::info( "Waiting for disconnection over LE:{}, BR/EDR:{} for pseudo address: {}, identity " diff --git a/system/bta/dm/bta_dm_disc.cc b/system/bta/dm/bta_dm_disc.cc index b3f010e86e..79d3421361 100644 --- a/system/bta/dm/bta_dm_disc.cc +++ b/system/bta/dm/bta_dm_disc.cc @@ -152,8 +152,7 @@ gatt_interface_t& get_gatt_interface() { return *gatt_interface; } void bta_dm_disc_gatt_cancel_open(const RawAddress& bd_addr) { get_gatt_interface().BTA_GATTC_CancelOpen(0, bd_addr, false); - if (com::android::bluetooth::flags::cancel_open_discovery_client() && - bta_dm_discovery_cb.client_if != BTA_GATTS_INVALID_IF) { + if (bta_dm_discovery_cb.client_if != BTA_GATTS_INVALID_IF) { get_gatt_interface().BTA_GATTC_CancelOpen(bta_dm_discovery_cb.client_if, bd_addr, true); } } @@ -559,11 +558,7 @@ static void bta_dm_gatt_disc_complete(tCONN_ID conn_id, tGATT_STATUS status) { } else { log::info("Discovery complete for invalid conn ID. Will pick up next job"); - if (com::android::bluetooth::flags::cancel_open_discovery_client()) { - bta_dm_close_gatt_conn(bta_dm_discovery_cb.conn_id); - } else { - bta_dm_discovery_cb.conn_id = GATT_INVALID_CONN_ID; - } + bta_dm_close_gatt_conn(bta_dm_discovery_cb.conn_id); if (bta_dm_discovery_cb.transports & BT_TRANSPORT_BR_EDR) { log::info("classic discovery still pending {}", bta_dm_discovery_cb.peer_bdaddr); return; diff --git a/system/bta/dm/bta_dm_int.h b/system/bta/dm/bta_dm_int.h index 521a8072de..26f7e4d97c 100644 --- a/system/bta/dm/bta_dm_int.h +++ b/system/bta/dm/bta_dm_int.h @@ -81,7 +81,7 @@ inline std::string device_info_text(tBTA_DM_DEV_INFO info) { #define BTA_DM_PM_EXECUTE 3 typedef uint8_t tBTA_DM_PM_REQ; -struct tBTA_DM_REMOVE_PENDNIG { +struct tBTA_DM_REMOVE_PENDING { RawAddress pseudo_addr; RawAddress identity_addr; bool le_connected; @@ -215,7 +215,7 @@ typedef struct { #endif alarm_t* switch_delay_timer; - std::list<tBTA_DM_REMOVE_PENDNIG> pending_removals; + std::list<tBTA_DM_REMOVE_PENDING> pending_removals; } tBTA_DM_CB; /* DI control block */ diff --git a/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc index 3b6069b1a1..346d7c3d6a 100644 --- a/system/bta/gatt/bta_gattc_act.cc +++ b/system/bta/gatt/bta_gattc_act.cc @@ -132,28 +132,17 @@ void bta_gattc_disable() { return; } - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - if (!bta_gattc_cb.cl_rcb_map.empty()) { - bta_gattc_cb.state = BTA_GATTC_STATE_DISABLING; - } - - // An entry can be erased during deregister, use a copied collection - std::vector<tGATT_IF> gatt_ifs; - for (auto& [gatt_if, p_rcb] : bta_gattc_cb.cl_rcb_map) { - gatt_ifs.push_back(gatt_if); - } - for (auto& gatt_if : gatt_ifs) { - bta_gattc_deregister(bta_gattc_cb.cl_rcb_map[gatt_if].get()); - } - } else { - for (i = 0; i < BTA_GATTC_CL_MAX; i++) { - if (!bta_gattc_cb.cl_rcb[i].in_use) { - continue; - } + if (!bta_gattc_cb.cl_rcb_map.empty()) { + bta_gattc_cb.state = BTA_GATTC_STATE_DISABLING; + } - bta_gattc_cb.state = BTA_GATTC_STATE_DISABLING; - bta_gattc_deregister(&bta_gattc_cb.cl_rcb[i]); - } + // An entry can be erased during deregister, use a copied collection + std::vector<tGATT_IF> gatt_ifs; + for (auto& [gatt_if, p_rcb] : bta_gattc_cb.cl_rcb_map) { + gatt_ifs.push_back(gatt_if); + } + for (auto& gatt_if : gatt_ifs) { + bta_gattc_deregister(bta_gattc_cb.cl_rcb_map[gatt_if].get()); } /* no registered apps, indicate disable completed */ @@ -187,55 +176,25 @@ void bta_gattc_register(const Uuid& app_uuid, const std::string& name, tBTA_GATT bta_gattc_enable(); } - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - client_if = GATT_Register(app_uuid, name, &bta_gattc_cl_cback, eatt_support); - if (client_if == 0) { - log::error("Register with GATT stack failed"); - status = GATT_ERROR; - } else { - auto p_rcb = std::make_unique<tBTA_GATTC_RCB>(); - p_rcb->in_use = true; - p_rcb->p_cback = p_cback; - p_rcb->app_uuid = app_uuid; - p_rcb->client_if = client_if; - bta_gattc_cb.cl_rcb_map.emplace(client_if, std::move(p_rcb)); - - log::debug( - "Registered GATT client interface {} with uuid={}, starting it on " - "main thread", - client_if, app_uuid.ToString()); - - do_in_main_thread(base::BindOnce(&bta_gattc_start_if, client_if)); - status = GATT_SUCCESS; - } + client_if = GATT_Register(app_uuid, name, &bta_gattc_cl_cback, eatt_support); + if (client_if == 0) { + log::error("Register with GATT stack failed"); + status = GATT_ERROR; } else { - for (uint8_t i = 0; i < BTA_GATTC_CL_MAX; i++) { - if (!bta_gattc_cb.cl_rcb[i].in_use) { - bta_gattc_cb.cl_rcb[i].client_if = - GATT_Register(app_uuid, "GattClient", &bta_gattc_cl_cback, eatt_support); - if (bta_gattc_cb.cl_rcb[i].client_if == 0) { - log::error("Register with GATT stack failed with index {}, trying next index", i); - status = GATT_ERROR; - } else { - bta_gattc_cb.cl_rcb[i].in_use = true; - bta_gattc_cb.cl_rcb[i].p_cback = p_cback; - bta_gattc_cb.cl_rcb[i].app_uuid = app_uuid; - - /* BTA use the same client interface as BTE GATT statck */ - client_if = bta_gattc_cb.cl_rcb[i].client_if; - - log::debug( - "Registered GATT client interface {} with uuid={}, starting it on " - "main thread", - client_if, app_uuid.ToString()); - - do_in_main_thread(base::BindOnce(&bta_gattc_start_if, client_if)); - - status = GATT_SUCCESS; - break; - } - } - } + auto p_rcb = std::make_unique<tBTA_GATTC_RCB>(); + p_rcb->in_use = true; + p_rcb->p_cback = p_cback; + p_rcb->app_uuid = app_uuid; + p_rcb->client_if = client_if; + bta_gattc_cb.cl_rcb_map.emplace(client_if, std::move(p_rcb)); + + log::debug( + "Registered GATT client interface {} with uuid={}, starting it on " + "main thread", + client_if, app_uuid.ToString()); + + do_in_main_thread(base::BindOnce(&bta_gattc_start_if, client_if)); + status = GATT_SUCCESS; } if (!cb.is_null()) { @@ -258,26 +217,13 @@ void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg) { continue; } - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - if (bta_gattc_cb.bg_track[i].cif_set.contains(p_clreg->client_if)) { - bta_gattc_mark_bg_conn(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); - if (!GATT_CancelConnect(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false)) { - log::warn( - "Unable to cancel GATT connection client_if:{} peer:{} " - "is_direct:{}", - p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); - } - } - } else { - if (bta_gattc_cb.bg_track[i].cif_mask & - ((tBTA_GATTC_CIF_MASK)1 << (p_clreg->client_if - 1))) { - bta_gattc_mark_bg_conn(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); - if (!GATT_CancelConnect(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false)) { - log::warn( - "Unable to cancel GATT connection client_if:{} peer:{} " - "is_direct:{}", - p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); - } + if (bta_gattc_cb.bg_track[i].cif_set.contains(p_clreg->client_if)) { + bta_gattc_mark_bg_conn(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); + if (!GATT_CancelConnect(p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false)) { + log::warn( + "Unable to cancel GATT connection client_if:{} peer:{} " + "is_direct:{}", + p_clreg->client_if, bta_gattc_cb.bg_track[i].remote_bda, false); } } } @@ -288,38 +234,23 @@ void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg) { } /* close all CLCB related to this app */ - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& p_clcb : bta_gattc_cb.clcb_set) { - if (!p_clcb->in_use || p_clcb->p_rcb != p_clreg) { - continue; - } - p_clreg->dereg_pending = true; - - tBTA_GATTC_DATA gattc_data = { - .hdr = - { - .event = BTA_GATTC_API_CLOSE_EVT, - .layer_specific = static_cast<uint16_t>(p_clcb->bta_conn_id), - }, - }; - bta_gattc_close(p_clcb.get(), &gattc_data); - } - // deallocated clcbs will not be accessed. Let them be claened up. - bta_gattc_cleanup_clcb(); - } else { - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - if (!bta_gattc_cb.clcb[i].in_use || (bta_gattc_cb.clcb[i].p_rcb != p_clreg)) { - continue; - } - - p_clreg->dereg_pending = true; - - BT_HDR_RIGID buf; - buf.event = BTA_GATTC_API_CLOSE_EVT; - buf.layer_specific = static_cast<uint16_t>(bta_gattc_cb.clcb[i].bta_conn_id); - bta_gattc_close(&bta_gattc_cb.clcb[i], (tBTA_GATTC_DATA*)&buf); + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (!p_clcb->in_use || p_clcb->p_rcb != p_clreg) { + continue; } + p_clreg->dereg_pending = true; + + tBTA_GATTC_DATA gattc_data = { + .hdr = + { + .event = BTA_GATTC_API_CLOSE_EVT, + .layer_specific = static_cast<uint16_t>(p_clcb->bta_conn_id), + }, + }; + bta_gattc_close(p_clcb.get(), &gattc_data); } + // deallocated clcbs will not be accessed. Let them be claened up. + bta_gattc_cleanup_clcb(); } /** process connect API request */ @@ -736,21 +667,12 @@ void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { /** when a SRCB finished discovery, tell all related clcb */ void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb, tGATT_STATUS status) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& p_clcb : bta_gattc_cb.clcb_set) { - if (p_clcb->p_srcb != p_srcb) { - continue; - } - p_clcb->status = status; - bta_gattc_sm_execute(p_clcb.get(), BTA_GATTC_DISCOVER_CMPL_EVT, NULL); - } - } else { - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) { - bta_gattc_cb.clcb[i].status = status; - bta_gattc_sm_execute(&bta_gattc_cb.clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT, NULL); - } + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (p_clcb->p_srcb != p_srcb) { + continue; } + p_clcb->status = status; + bta_gattc_sm_execute(p_clcb.get(), BTA_GATTC_DISCOVER_CMPL_EVT, NULL); } } @@ -777,23 +699,13 @@ void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data /** when a SRCB start discovery, tell all related clcb and set the state */ static void bta_gattc_set_discover_st(tBTA_GATTC_SERV* p_srcb) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& p_clcb : bta_gattc_cb.clcb_set) { - if (p_clcb->p_srcb != p_srcb) { - continue; - } - p_clcb->status = GATT_SUCCESS; - p_clcb->state = BTA_GATTC_DISCOVER_ST; - p_clcb->request_during_discovery = BTA_GATTC_DISCOVER_REQ_NONE; - } - } else { - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) { - bta_gattc_cb.clcb[i].status = GATT_SUCCESS; - bta_gattc_cb.clcb[i].state = BTA_GATTC_DISCOVER_ST; - bta_gattc_cb.clcb[i].request_during_discovery = BTA_GATTC_DISCOVER_REQ_NONE; - } + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (p_clcb->p_srcb != p_srcb) { + continue; } + p_clcb->status = GATT_SUCCESS; + p_clcb->state = BTA_GATTC_DISCOVER_ST; + p_clcb->request_during_discovery = BTA_GATTC_DISCOVER_REQ_NONE; } } @@ -1422,12 +1334,8 @@ static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB* p_clreg) { memset(&cb_data, 0, sizeof(tBTA_GATTC)); GATT_Deregister(p_clreg->client_if); - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - if (bta_gattc_cb.cl_rcb_map.erase(p_clreg->client_if) == 0) { - log::warn("deregistered unknown rcb client_if={}", p_clreg->client_if); - } - } else { - memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB)); + if (bta_gattc_cb.cl_rcb_map.erase(p_clreg->client_if) == 0) { + log::warn("deregistered unknown rcb client_if={}", p_clreg->client_if); } cb_data.reg_oper.client_if = client_if; @@ -1490,20 +1398,11 @@ void bta_gattc_process_api_refresh(const RawAddress& remote_bda) { if (p_srvc_cb->connected && p_srvc_cb->num_clcb != 0) { bool found = false; tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0]; - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& p_clcb_i : bta_gattc_cb.clcb_set) { - if (p_clcb_i->in_use && p_clcb_i->p_srcb == p_srvc_cb) { - p_clcb = p_clcb_i.get(); - found = true; - break; - } - } - } else { - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) { - if (p_clcb->in_use && p_clcb->p_srcb == p_srvc_cb) { - found = true; - break; - } + for (auto& p_clcb_i : bta_gattc_cb.clcb_set) { + if (p_clcb_i->in_use && p_clcb_i->p_srcb == p_srvc_cb) { + p_clcb = p_clcb_i.get(); + found = true; + break; } } if (found) { @@ -1563,38 +1462,19 @@ static bool bta_gattc_process_srvc_chg_ind(tCONN_ID conn_id, tBTA_GATTC_RCB* p_c /* not an opened connection; or connection busy */ /* search for first available clcb and start discovery */ if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& p_clcb_i : bta_gattc_cb.clcb_set) { - if (p_clcb_i->in_use && p_clcb_i->p_srcb == p_srcb && p_clcb_i->p_q_cmd == NULL) { - p_clcb = p_clcb_i.get(); - break; - } - } - } else { - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - if (bta_gattc_cb.clcb[i].in_use && bta_gattc_cb.clcb[i].p_srcb == p_srcb && - bta_gattc_cb.clcb[i].p_q_cmd == NULL) { - p_clcb = &bta_gattc_cb.clcb[i]; - break; - } + for (auto& p_clcb_i : bta_gattc_cb.clcb_set) { + if (p_clcb_i->in_use && p_clcb_i->p_srcb == p_srcb && p_clcb_i->p_q_cmd == NULL) { + p_clcb = p_clcb_i.get(); + break; } } } // Use a busy CLCB to start discovery if no CLCB is available, this will be queued. if (com::android::bluetooth::flags::start_discover_service_changed() && p_clcb == NULL) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& p_clcb_i : bta_gattc_cb.clcb_set) { - if (p_clcb_i->in_use && p_clcb_i->p_srcb == p_srcb) { - p_clcb = p_clcb_i.get(); - break; - } - } - } else { - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - if (bta_gattc_cb.clcb[i].in_use && bta_gattc_cb.clcb[i].p_srcb == p_srcb) { - p_clcb = &bta_gattc_cb.clcb[i]; - break; - } + for (auto& p_clcb_i : bta_gattc_cb.clcb_set) { + if (p_clcb_i->in_use && p_clcb_i->p_srcb == p_srcb) { + p_clcb = p_clcb_i.get(); + break; } } } diff --git a/system/bta/gatt/bta_gattc_utils.cc b/system/bta/gatt/bta_gattc_utils.cc index 23b150b829..523cf90fe5 100644 --- a/system/bta/gatt/bta_gattc_utils.cc +++ b/system/bta/gatt/bta_gattc_utils.cc @@ -25,7 +25,6 @@ #define LOG_TAG "bt_bta_gattc" #include <bluetooth/log.h> -#include <com_android_bluetooth_flags.h> #include <cstdint> @@ -58,23 +57,11 @@ static uint8_t ble_acceptlist_size() { * ******************************************************************************/ tBTA_GATTC_RCB* bta_gattc_cl_get_regcb(uint8_t client_if) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - auto it = bta_gattc_cb.cl_rcb_map.find(client_if); - if (it == bta_gattc_cb.cl_rcb_map.end()) { - return NULL; - } else { - return it->second.get(); - } - } else { - uint8_t i = 0; - tBTA_GATTC_RCB* p_clrcb = &bta_gattc_cb.cl_rcb[0]; - - for (i = 0; i < BTA_GATTC_CL_MAX; i++, p_clrcb++) { - if (p_clrcb->in_use && p_clrcb->client_if == client_if) { - return p_clrcb; - } - } + auto it = bta_gattc_cb.cl_rcb_map.find(client_if); + if (it == bta_gattc_cb.cl_rcb_map.end()) { return NULL; + } else { + return it->second.get(); } } /******************************************************************************* @@ -86,20 +73,7 @@ tBTA_GATTC_RCB* bta_gattc_cl_get_regcb(uint8_t client_if) { * Returns pointer to the regcb * ******************************************************************************/ -uint8_t bta_gattc_num_reg_app(void) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - return (uint8_t)bta_gattc_cb.cl_rcb_map.size(); - } else { - uint8_t i = 0, j = 0; - - for (i = 0; i < BTA_GATTC_CL_MAX; i++) { - if (bta_gattc_cb.cl_rcb[i].in_use) { - j++; - } - } - return j; - } -} +uint8_t bta_gattc_num_reg_app(void) { return (uint8_t)bta_gattc_cb.cl_rcb_map.size(); } /******************************************************************************* * * Function bta_gattc_find_clcb_by_cif @@ -111,21 +85,10 @@ uint8_t bta_gattc_num_reg_app(void) { ******************************************************************************/ tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_cif(uint8_t client_if, const RawAddress& remote_bda, tBT_TRANSPORT transport) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& p_clcb : bta_gattc_cb.clcb_set) { - if (p_clcb->in_use && p_clcb->p_rcb->client_if == client_if && - p_clcb->transport == transport && p_clcb->bda == remote_bda) { - return p_clcb.get(); - } - } - } else { - tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0]; - - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) { - if (p_clcb->in_use && p_clcb->p_rcb->client_if == client_if && - p_clcb->transport == transport && p_clcb->bda == remote_bda) { - return p_clcb; - } + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (p_clcb->in_use && p_clcb->p_rcb->client_if == client_if && p_clcb->transport == transport && + p_clcb->bda == remote_bda) { + return p_clcb.get(); } } return NULL; @@ -140,19 +103,9 @@ tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_cif(uint8_t client_if, const RawAddress& * ******************************************************************************/ tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_conn_id(tCONN_ID conn_id) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& p_clcb : bta_gattc_cb.clcb_set) { - if (p_clcb->in_use && p_clcb->bta_conn_id == conn_id) { - return p_clcb.get(); - } - } - } else { - tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0]; - - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) { - if (p_clcb->in_use && p_clcb->bta_conn_id == conn_id) { - return p_clcb; - } + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (p_clcb != NULL && p_clcb->in_use && p_clcb->bta_conn_id == conn_id) { + return p_clcb.get(); } } return NULL; @@ -171,63 +124,30 @@ tBTA_GATTC_CLCB* bta_gattc_clcb_alloc(tGATT_IF client_if, const RawAddress& remo tBT_TRANSPORT transport) { tBTA_GATTC_CLCB* p_clcb = NULL; - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - bta_gattc_cleanup_clcb(); - auto [p_clcb_i, b] = bta_gattc_cb.clcb_set.emplace(std::make_unique<tBTA_GATTC_CLCB>()); - p_clcb = p_clcb_i->get(); + bta_gattc_cleanup_clcb(); + auto [p_clcb_i, b] = bta_gattc_cb.clcb_set.emplace(std::make_unique<tBTA_GATTC_CLCB>()); + p_clcb = p_clcb_i->get(); - p_clcb->in_use = true; - p_clcb->status = GATT_SUCCESS; - p_clcb->transport = transport; - p_clcb->bda = remote_bda; - p_clcb->p_q_cmd = NULL; + p_clcb->in_use = true; + p_clcb->status = GATT_SUCCESS; + p_clcb->transport = transport; + p_clcb->bda = remote_bda; + p_clcb->p_q_cmd = NULL; - p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if); + p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if); - p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda); - if (p_clcb->p_srcb == NULL) { - p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda); - } + p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda); + if (p_clcb->p_srcb == NULL) { + p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda); + } - if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) { - p_clcb->p_srcb->num_clcb++; - p_clcb->p_rcb->num_clcb++; - } else { - /* release this clcb if clcb or srcb allocation failed */ - bta_gattc_cb.clcb_set.erase(p_clcb_i); - p_clcb = NULL; - } + if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) { + p_clcb->p_srcb->num_clcb++; + p_clcb->p_rcb->num_clcb++; } else { - for (int i_clcb = 0; i_clcb < BTA_GATTC_CLCB_MAX; i_clcb++) { - if (!bta_gattc_cb.clcb[i_clcb].in_use) { -#if (BTA_GATT_DEBUG == TRUE) - log::verbose("found clcb:{} available", i_clcb); -#endif - p_clcb = &bta_gattc_cb.clcb[i_clcb]; - p_clcb->in_use = true; - p_clcb->status = GATT_SUCCESS; - p_clcb->transport = transport; - p_clcb->bda = remote_bda; - p_clcb->p_q_cmd = NULL; - - p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if); - - p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda); - if (p_clcb->p_srcb == NULL) { - p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda); - } - - if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) { - p_clcb->p_srcb->num_clcb++; - p_clcb->p_rcb->num_clcb++; - } else { - /* release this clcb if clcb or srcb allocation failed */ - p_clcb->in_use = false; - p_clcb = NULL; - } - break; - } - } + /* release this clcb if clcb or srcb allocation failed */ + bta_gattc_cb.clcb_set.erase(p_clcb_i); + p_clcb = NULL; } return p_clcb; } @@ -330,9 +250,7 @@ void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB* p_clcb) { p_clcb->status = GATT_SUCCESS; // in bta_gattc_sm_execute(), p_clcb is accessed again so we dealloc clcb later. // it will be claned up when the client is deregistered or a new clcb is allocated. - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - bta_gattc_cb.clcb_pending_dealloc.insert(p_clcb); - } + bta_gattc_cb.clcb_pending_dealloc.insert(p_clcb); } /******************************************************************************* @@ -643,39 +561,21 @@ bool bta_gattc_mark_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda_ptr for (i = 0; i < ble_acceptlist_size(); i++, p_bg_tck++) { if (p_bg_tck->in_use && ((p_bg_tck->remote_bda == remote_bda_ptr) || (p_bg_tck->remote_bda.IsEmpty()))) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - auto& p_cif_set = p_bg_tck->cif_set; - if (add) { /* mask on the cif bit */ - p_cif_set.insert(client_if); - } else { - if (client_if != 0) { - p_cif_set.erase(client_if); - } else { - p_cif_set.clear(); - } - } - /* no BG connection for this device, make it available */ - if (p_bg_tck->cif_set.empty()) { - p_bg_tck->in_use = false; - p_bg_tck->remote_bda = RawAddress::kEmpty; - } + auto& p_cif_set = p_bg_tck->cif_set; + if (add) { /* mask on the cif bit */ + p_cif_set.insert(client_if); } else { - p_cif_mask = &p_bg_tck->cif_mask; - - if (add) { /* mask on the cif bit */ - *p_cif_mask |= (1 << (client_if - 1)); + if (client_if != 0) { + p_cif_set.erase(client_if); } else { - if (client_if != 0) { - *p_cif_mask &= (~(1 << (client_if - 1))); - } else { - *p_cif_mask = 0; - } - } - /* no BG connection for this device, make it available */ - if (p_bg_tck->cif_mask == 0) { - *p_bg_tck = tBTA_GATTC_BG_TCK{}; + p_cif_set.clear(); } } + /* no BG connection for this device, make it available */ + if (p_bg_tck->cif_set.empty()) { + p_bg_tck->in_use = false; + p_bg_tck->remote_bda = RawAddress::kEmpty; + } return true; } } @@ -688,12 +588,7 @@ bool bta_gattc_mark_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda_ptr p_bg_tck->in_use = true; p_bg_tck->remote_bda = remote_bda_ptr; - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - p_bg_tck->cif_set = {client_if}; - } else { - p_cif_mask = &p_bg_tck->cif_mask; - *p_cif_mask = ((tBTA_GATTC_CIF_MASK)1 << (client_if - 1)); - } + p_bg_tck->cif_set = {client_if}; return true; } } @@ -719,15 +614,8 @@ bool bta_gattc_check_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda, u for (i = 0; i < ble_acceptlist_size() && !is_bg_conn; i++, p_bg_tck++) { if (p_bg_tck->in_use && (p_bg_tck->remote_bda == remote_bda || p_bg_tck->remote_bda.IsEmpty())) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - if (p_bg_tck->cif_set.contains(client_if) && role == HCI_ROLE_CENTRAL) { - is_bg_conn = true; - } - } else { - if (((p_bg_tck->cif_mask & ((tBTA_GATTC_CIF_MASK)1 << (client_if - 1))) != 0) && - role == HCI_ROLE_CENTRAL) { - is_bg_conn = true; - } + if (p_bg_tck->cif_set.contains(client_if) && role == HCI_ROLE_CENTRAL) { + is_bg_conn = true; } } } @@ -938,58 +826,28 @@ void bta_gatt_client_dump(int fd) { stream << " -- used: " << entry_count << "\n"; entry_count = 0; - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - stream << " ->cl_rcb (dynamic)\n"; - for (auto& [i, p_cl_rcb] : bta_gattc_cb.cl_rcb_map) { - entry_count++; - stream << " client_if: " << +p_cl_rcb->client_if << " app uuids: " << p_cl_rcb->app_uuid - << " clcb_num: " << +p_cl_rcb->num_clcb; - stream << "\n"; - } - } else { - stream << " ->cl_rcb (BTA_GATTC_CL_MAX=" << BTA_GATTC_CL_MAX << ")\n"; - for (int i = 0; i < BTA_GATTC_CL_MAX; i++) { - tBTA_GATTC_RCB* p_cl_rcb = &bta_gattc_cb.cl_rcb[i]; - if (!p_cl_rcb->in_use) { - continue; - } - entry_count++; - stream << " client_if: " << +p_cl_rcb->client_if << " app uuids: " << p_cl_rcb->app_uuid - << " clcb_num: " << +p_cl_rcb->num_clcb; - stream << "\n"; - } + stream << " ->cl_rcb (dynamic)\n"; + for (auto& [i, p_cl_rcb] : bta_gattc_cb.cl_rcb_map) { + entry_count++; + stream << " client_if: " << +p_cl_rcb->client_if << " app uuids: " << p_cl_rcb->app_uuid + << " clcb_num: " << +p_cl_rcb->num_clcb; + stream << "\n"; } stream << " -- used: " << entry_count << "\n"; entry_count = 0; - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - stream << " ->clcb (dynamic)\n"; - for (auto& p_clcb : bta_gattc_cb.clcb_set) { - if (!p_clcb->in_use) { - continue; - } - entry_count++; - stream << " conn_id: " << loghex(p_clcb->bta_conn_id) - << " address: " << p_clcb->bda.ToRedactedStringForLogging() - << " transport: " << bt_transport_text(p_clcb->transport) - << " state: " << bta_clcb_state_text(p_clcb->state); - stream << "\n"; - } - } else { - stream << " ->clcb (BTA_GATTC_CLCB_MAX=" << BTA_GATTC_CLCB_MAX << ")\n"; - for (size_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) { - tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[i]; - if (!p_clcb->in_use) { - continue; - } - entry_count++; - stream << " conn_id: " << loghex(p_clcb->bta_conn_id) - << " address: " << p_clcb->bda.ToRedactedStringForLogging() - << " transport: " << bt_transport_text(p_clcb->transport) - << " state: " << bta_clcb_state_text(p_clcb->state); - stream << "\n"; + stream << " ->clcb (dynamic)\n"; + for (auto& p_clcb : bta_gattc_cb.clcb_set) { + if (!p_clcb->in_use) { + continue; } + entry_count++; + stream << " conn_id: " << loghex(p_clcb->bta_conn_id) + << " address: " << p_clcb->bda.ToRedactedStringForLogging() + << " transport: " << bt_transport_text(p_clcb->transport) + << " state: " << bta_clcb_state_text(p_clcb->state); + stream << "\n"; } stream << " -- used: " << entry_count << "\n"; diff --git a/system/bta/hearing_aid/OWNERS b/system/bta/hearing_aid/OWNERS deleted file mode 100644 index bbaa85ddbb..0000000000 --- a/system/bta/hearing_aid/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_hearingaid diff --git a/system/bta/hearing_aid/hearing_aid_test.cc b/system/bta/hearing_aid/hearing_aid_test.cc new file mode 100644 index 0000000000..2090df9d81 --- /dev/null +++ b/system/bta/hearing_aid/hearing_aid_test.cc @@ -0,0 +1,474 @@ +/* + * Copyright 2025 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 <base/bind_helpers.h> +#include <base/functional/bind.h> +#include <base/strings/string_number_conversions.h> +#include <bluetooth/log.h> +#include <com_android_bluetooth_flags.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <log/log.h> +#include <osi/include/alarm.h> +#include <string.h> +#include <sys/socket.h> + +#include <variant> + +#include "bta/le_audio/le_audio_types.h" +#include "bta_gatt_api_mock.h" +#include "bta_gatt_queue_mock.h" +#include "bta_hearing_aid_api.h" +#include "btif_storage_mock.h" +#include "btm_api_mock.h" +#include "gatt/database_builder.h" +#include "hardware/bt_gatt_types.h" +#include "hci/controller_interface_mock.h" +#include "stack/include/bt_uuid16.h" +#include "stack/include/btm_status.h" +#include "test/common/mock_functions.h" +#include "test/mock/mock_main_shim_entry.h" +#include "test/mock/mock_stack_gap_conn_interface.h" +#include "test/mock/mock_stack_l2cap_interface.h" +#include "types/bt_transport.h" + +static std::map<const char*, bool> fake_osi_bool_props; + +namespace bluetooth { +namespace hearing_aid { +namespace internal { +namespace { + +using base::HexEncode; + +using namespace bluetooth::hearing_aid; + +using ::bluetooth::hearing_aid::ConnectionState; +using ::bluetooth::hearing_aid::HearingAidCallbacks; +using ::bluetooth::hearing_aid::HearingAidInterface; + +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::DoAll; +using ::testing::DoDefault; +using ::testing::Invoke; +using ::testing::Mock; +using ::testing::NiceMock; +using ::testing::NotNull; +using ::testing::Return; +using ::testing::SaveArg; +using ::testing::Sequence; +using ::testing::SetArgPointee; +using ::testing::WithArg; + +RawAddress GetTestAddress(int index) { + CHECK_LT(index, UINT8_MAX); + RawAddress result = {{0xC0, 0xDE, 0xC0, 0xDE, 0x00, static_cast<uint8_t>(index)}}; + return result; +} + +static uint16_t GetTestConnId(const RawAddress& address) { + return address.address[RawAddress::kLength - 1]; +} + +class MockHearingAidCallbacks : public HearingAidCallbacks { +public: + MockHearingAidCallbacks() = default; + MockHearingAidCallbacks(const MockHearingAidCallbacks&) = delete; + ~MockHearingAidCallbacks() override = default; + + MOCK_METHOD((void), OnConnectionState, (ConnectionState state, const RawAddress& address), + (override)); + MOCK_METHOD((void), OnDeviceAvailable, + (uint8_t capabilities, uint64_t hiSyncId, const RawAddress& address), (override)); +}; + +class HearingAidTestBase : public ::testing::Test { +protected: + Uuid HEARING_AID_UUID = Uuid::FromString("FDF0"); + Uuid READ_ONLY_PROPERTIES_UUID = Uuid::FromString("6333651e-c481-4a3e-9169-7c902aad37bb"); + Uuid AUDIO_CONTROL_POINT_UUID = Uuid::FromString("f0d4de7e-4a88-476c-9d9f-1937b0996cc0"); + Uuid AUDIO_STATUS_UUID = Uuid::FromString("38663f1a-e711-4cac-b641-326b56404837"); + Uuid VOLUME_UUID = Uuid::FromString("00e4ca9e-ab14-41e4-8823-f9e70c7e91df"); + Uuid LE_PSM_UUID = Uuid::FromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a"); + + void set_sample_database(uint16_t conn_id) { + static constexpr uint16_t kGapSvcStartHdl = 0x0001; + static constexpr uint16_t kGapDeviceNameValHdl = 0x0003; + static constexpr uint16_t kGapSvcEndHdl = kGapDeviceNameValHdl; + + static constexpr uint16_t kSvcStartHdl = 0x0010; + static constexpr uint16_t kReadOnlyProperties = 0x0012; + static constexpr uint16_t kAudioControlPoint = 0x0015; + static constexpr uint16_t kAudioStatusPoint = 0x0018; + static constexpr uint16_t kVolume = 0x001B; + static constexpr uint16_t kLePsm = 0x001E; + static constexpr uint16_t kSvcEndHdl = kLePsm; + + gatt::DatabaseBuilder bob; + + /* Generic Access Service */ + bob.AddService(kGapSvcStartHdl, kGapDeviceNameValHdl, Uuid::From16Bit(0x1800), true); + /* Device Name Char. */ + bob.AddCharacteristic(kGapDeviceNameValHdl - 1, kGapDeviceNameValHdl, Uuid::From16Bit(0x2a00), + GATT_CHAR_PROP_BIT_READ); + + /* ASHA Service */ + bob.AddService(kSvcStartHdl, kSvcEndHdl, HEARING_AID_UUID, true); + bob.AddCharacteristic(kReadOnlyProperties - 1, kReadOnlyProperties, READ_ONLY_PROPERTIES_UUID, + GATT_CHAR_PROP_BIT_READ); + bob.AddCharacteristic(kAudioControlPoint - 1, kAudioControlPoint, AUDIO_CONTROL_POINT_UUID, + GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE_NR); + bob.AddCharacteristic(kAudioStatusPoint - 1, kAudioStatusPoint, AUDIO_STATUS_UUID, + GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY); + bob.AddDescriptor(kAudioStatusPoint + 1, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG)); + bob.AddCharacteristic(kVolume - 1, kVolume, VOLUME_UUID, GATT_CHAR_PROP_BIT_WRITE_NR); + bob.AddCharacteristic(kLePsm - 1, kLePsm, LE_PSM_UUID, GATT_CHAR_PROP_BIT_READ); + + services_map[conn_id] = bob.Build().Services(); + + ON_CALL(gatt_queue, ReadCharacteristic(conn_id, _, _, _)) + .WillByDefault(Invoke( + [this](uint16_t conn_id, uint16_t handle, GATT_READ_OP_CB cb, void* cb_data) { + auto* svc = gatt::FindService(services_map[conn_id], handle); + if (svc == nullptr) { + return; + } + + std::vector<uint8_t> value; + tGATT_STATUS status = GATT_SUCCESS; + + switch (handle) { + case kReadOnlyProperties: + value.resize(17); + value.assign(17, 0x01); + break; + case kAudioStatusPoint: + value.resize(1); + value.assign(1, 0); + break; + case kLePsm: + value.resize(2); + value.assign(2, 0x0080); + break; + /* passthrough */ + default: + status = GATT_READ_NOT_PERMIT; + break; + } + + if (cb) { + cb(conn_id, status, handle, value.size(), value.data(), cb_data); + } + })); + + /* default action for GetCharacteristic function call */ + ON_CALL(gatt_interface, GetCharacteristic(_, _)) + .WillByDefault( + Invoke([&](uint16_t conn_id, uint16_t handle) -> const gatt::Characteristic* { + std::list<gatt::Service>& services = services_map[conn_id]; + for (auto const& service : services) { + for (auto const& characteristic : service.characteristics) { + if (characteristic.value_handle == handle) { + return &characteristic; + } + } + } + + return nullptr; + })); + + ON_CALL(gatt_interface, ServiceSearchRequest(_, _)) + .WillByDefault(WithArg<0>( + Invoke([&](uint16_t conn_id) { InjectSearchCompleteEvent(conn_id); }))); + + /* default action for GetServices function call */ + ON_CALL(gatt_interface, GetServices(_)) + .WillByDefault(WithArg<0>(Invoke([&](uint16_t conn_id) -> std::list<gatt::Service>* { + return &services_map[conn_id]; + }))); + + /* default action for RegisterForNotifications function call */ + ON_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _)) + .WillByDefault(Return(GATT_SUCCESS)); + + /* default action for DeregisterForNotifications function call */ + ON_CALL(gatt_interface, DeregisterForNotifications(gatt_if, _, _)) + .WillByDefault(Return(GATT_SUCCESS)); + + /* default action for WriteDescriptor function call */ + ON_CALL(gatt_queue, WriteDescriptor(_, _, _, _, _, _)) + .WillByDefault(Invoke([](uint16_t conn_id, uint16_t handle, std::vector<uint8_t> value, + tGATT_WRITE_TYPE /*write_type*/, GATT_WRITE_OP_CB cb, + void* cb_data) -> void { + if (cb) { + cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), cb_data); + } + })); + } + + void SetUp(void) override { + fake_osi_bool_props.clear(); + bluetooth::manager::SetMockBtmInterface(&btm_interface); + bluetooth::storage::SetMockBtifStorageInterface(&btif_storage_interface_); + gatt::SetMockBtaGattInterface(&gatt_interface); + gatt::SetMockBtaGattQueue(&gatt_queue); + callbacks.reset(new MockHearingAidCallbacks()); + bluetooth::hci::testing::mock_controller_ = + std::make_unique<NiceMock<bluetooth::hci::testing::MockControllerInterface>>(); + bluetooth::testing::stack::l2cap::set_interface(&mock_stack_l2cap_interface_); + bluetooth::testing::stack::gap_conn::set_interface(&mock_stack_gap_conn_interface_); + + encryption_result = true; + + ON_CALL(mock_stack_l2cap_interface_, L2CA_UpdateBleConnParams(_, _, _, _, _, _, _)) + .WillByDefault(Invoke([&](const RawAddress& /*rem_bda*/, uint16_t min_int, + uint16_t /*max_int*/, uint16_t latency, uint16_t timeout, + uint16_t /*min_ce_len*/, uint16_t /*max_ce_len*/) { + req_int = min_int; + req_latency = latency; + req_timeout = timeout; + return true; + })); + + ON_CALL(mock_stack_gap_conn_interface_, GAP_ConnOpen(_, _, _, _, _, _, _, _, _, _, _)) + .WillByDefault(Invoke([&](const char* /* p_serv_name */, uint8_t /*service_id*/, + bool /*is_server*/, const RawAddress* p_rem_bda, + uint16_t /*psm*/, uint16_t /*le_mps*/, + tL2CAP_CFG_INFO* /*p_cfg*/, tL2CAP_ERTM_INFO* /*ertm_info*/, + uint16_t /*security*/, tGAP_CONN_CALLBACK* p_cb, + tBT_TRANSPORT /*transport*/) { + InjectConnUpdateEvent(p_rem_bda->address[5], req_int, req_latency, req_timeout); + + gap_conn_cb = p_cb; + if (gap_conn_cb) { + gap_conn_cb(0xFFFF, GAP_EVT_CONN_OPENED, nullptr); + } + return 1; + })); + + ON_CALL(mock_stack_gap_conn_interface_, GAP_ConnGetRemoteAddr(_)) + .WillByDefault(Invoke([&](uint16_t /*gap_handle*/) { return &test_address; })); + + /* by default connect only direct connection requests */ + ON_CALL(gatt_interface, Open(_, _, _, _)) + .WillByDefault(Invoke([&](tGATT_IF /*client_if*/, const RawAddress& remote_bda, + tBTM_BLE_CONN_TYPE connection_type, bool /*opportunistic*/) { + if (connection_type == BTM_BLE_DIRECT_CONNECTION) { + InjectConnectedEvent(remote_bda, GetTestConnId(remote_bda)); + } + })); + + ON_CALL(gatt_interface, Close(_)).WillByDefault(Invoke([&](uint16_t conn_id) { + /* We arrive here once, when we call Disconnect; and second time, after + * we send OnGattDisconnected - but device was already removed */ + if (connected_devices.count(conn_id) > 0) { + InjectDisconnectedEvent(conn_id); + } + })); + } + + void TearDown(void) override { + services_map.clear(); + gatt::SetMockBtaGattQueue(nullptr); + gatt::SetMockBtaGattInterface(nullptr); + bluetooth::manager::SetMockBtmInterface(nullptr); + bluetooth::hci::testing::mock_controller_.reset(); + bluetooth::testing::stack::l2cap::reset_interface(); + bluetooth::testing::stack::gap_conn::reset_interface(); + Mock::VerifyAndClearExpectations(&*callbacks); + Mock::VerifyAndClearExpectations(&gatt_queue); + Mock::VerifyAndClearExpectations(&gatt_interface); + Mock::VerifyAndClearExpectations(&btm_interface); + callbacks.reset(); + } + + void InjectConnectedEvent(const RawAddress& address, uint16_t conn_id, + tGATT_STATUS status = GATT_SUCCESS) { + tBTA_GATTC_OPEN event_data = { + .status = status, + .conn_id = conn_id, + .client_if = gatt_if, + .remote_bda = address, + .transport = BT_TRANSPORT_LE, + .mtu = 240, + }; + connected_devices[conn_id] = address; + gatt_callback(BTA_GATTC_OPEN_EVT, (tBTA_GATTC*)&event_data); + } + + void InjectConnUpdateEvent(uint16_t conn_id, uint16_t interval, uint16_t latency, + uint16_t timeout, tGATT_STATUS status = GATT_SUCCESS) { + tBTA_GATTC_CONN_UPDATE event_data = { + .conn_id = conn_id, + .interval = interval, + .latency = latency, + .timeout = timeout, + .status = status, + }; + + gatt_callback(BTA_GATTC_CONN_UPDATE_EVT, (tBTA_GATTC*)&event_data); + } + + void InjectDisconnectedEvent(uint16_t conn_id, + tGATT_DISCONN_REASON reason = GATT_CONN_TERMINATE_LOCAL_HOST, + bool allow_fake_conn = false) { + if (!allow_fake_conn) { + ASSERT_NE(connected_devices.count(conn_id), 0u); + } + + tBTA_GATTC_CLOSE event_data = { + .conn_id = conn_id, + .status = GATT_SUCCESS, + .client_if = gatt_if, + .remote_bda = connected_devices[conn_id], + .reason = reason, + }; + + connected_devices.erase(conn_id); + gatt_callback(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC*)&event_data); + } + + void InjectSearchCompleteEvent(uint16_t conn_id) { + tBTA_GATTC_SEARCH_CMPL event_data = { + .conn_id = conn_id, + .status = GATT_SUCCESS, + }; + + gatt_callback(BTA_GATTC_SEARCH_CMPL_EVT, (tBTA_GATTC*)&event_data); + } + + void InjectNotificationEvent(const RawAddress& test_address, uint16_t conn_id, uint16_t handle, + std::vector<uint8_t> value, bool indicate = false) { + tBTA_GATTC_NOTIFY event_data = { + .conn_id = conn_id, + .bda = test_address, + .handle = handle, + .len = (uint8_t)value.size(), + .is_notify = !indicate, + }; + + ASSERT_TRUE(value.size() < GATT_MAX_ATTR_LEN); + std::copy(value.begin(), value.end(), event_data.value); + gatt_callback(BTA_GATTC_NOTIF_EVT, (tBTA_GATTC*)&event_data); + } + + void SetEncryptionResult(const RawAddress& address, bool success) { + encryption_result = success; + + ON_CALL(btm_interface, BTM_IsEncrypted(address, _)).WillByDefault(Return(encryption_result)); + + ON_CALL(btm_interface, IsDeviceBonded(address, _)).WillByDefault(Return(true)); + } + + std::unique_ptr<MockHearingAidCallbacks> callbacks; + bluetooth::manager::MockBtmInterface btm_interface; + bluetooth::storage::MockBtifStorageInterface btif_storage_interface_; + gatt::MockBtaGattInterface gatt_interface; + gatt::MockBtaGattQueue gatt_queue; + tBTA_GATTC_CBACK* gatt_callback; + const uint8_t gatt_if = 0xfe; + std::map<uint8_t, RawAddress> connected_devices; + std::map<uint16_t, std::list<gatt::Service>> services_map; + bluetooth::testing::stack::l2cap::Mock mock_stack_l2cap_interface_; + bluetooth::testing::stack::gap_conn::Mock mock_stack_gap_conn_interface_; + tGAP_CONN_CALLBACK* gap_conn_cb; + uint16_t req_int; + uint16_t req_latency; + uint16_t req_timeout; + bool encryption_result; + const RawAddress test_address = GetTestAddress(1); +}; + +class HearingAidTest : public HearingAidTestBase { + void SetUp(void) override { + HearingAidTestBase::SetUp(); + BtaAppRegisterCallback app_register_callback; + EXPECT_CALL(gatt_interface, AppRegister(_, _, _, _)) + .WillOnce(DoAll(SaveArg<1>(&gatt_callback), SaveArg<2>(&app_register_callback))); + HearingAid::Initialize(callbacks.get(), base::DoNothing()); + ASSERT_TRUE(gatt_callback); + ASSERT_TRUE(app_register_callback); + app_register_callback.Run(gatt_if, GATT_SUCCESS); + ASSERT_TRUE(HearingAid::IsHearingAidRunning()); + Mock::VerifyAndClearExpectations(&gatt_interface); + } + void TearDown(void) override { + EXPECT_CALL(gatt_interface, AppDeregister(gatt_if)); + if (HearingAid::IsHearingAidRunning()) { + HearingAid::CleanUp(); + } + ASSERT_FALSE(HearingAid::IsHearingAidRunning()); + gatt_callback = nullptr; + HearingAidTestBase::TearDown(); + } +}; + +/* Test that hearing aid is initialized and cleaned up */ +TEST_F(HearingAidTestBase, initialize) { + ASSERT_FALSE(HearingAid::IsHearingAidRunning()); + HearingAid::Initialize(callbacks.get(), base::DoNothing()); + ASSERT_TRUE(HearingAid::IsHearingAidRunning()); + HearingAid::CleanUp(); + ASSERT_FALSE(HearingAid::IsHearingAidRunning()); +} + +/* Test that connect cancellation works */ +TEST_F(HearingAidTest, disconnect_when_connecting) { + /* Override the default action to prevent us sending the connected event */ + EXPECT_CALL(gatt_interface, Open(gatt_if, test_address, BTM_BLE_DIRECT_CONNECTION, _)) + .WillOnce(Return()); + EXPECT_CALL(*callbacks, OnDeviceAvailable(_, _, test_address)).Times(0); + HearingAid::Connect(test_address); + + /* Single call from HearingAid:Disconnect*/ + EXPECT_CALL(*callbacks, OnConnectionState(ConnectionState::DISCONNECTED, test_address)).Times(1); + EXPECT_CALL(gatt_interface, CancelOpen(_, test_address, _)).Times(AnyNumber()); + EXPECT_CALL(gatt_interface, Close(_)).Times(0); + HearingAid::Disconnect(test_address); +} + +/* Test that connect works and Connected state gets reported */ +TEST_F(HearingAidTest, connect) { + set_sample_database(1); + + EXPECT_CALL(gatt_interface, Open(gatt_if, test_address, BTM_BLE_DIRECT_CONNECTION, _)); + EXPECT_CALL(*callbacks, OnConnectionState(ConnectionState::CONNECTED, test_address)); + EXPECT_CALL(*callbacks, OnDeviceAvailable(_, _, test_address)); + ON_CALL(btm_interface, BTM_IsEncrypted(test_address, _)).WillByDefault(Return(true)); + + HearingAid::Connect(test_address); +} + +/* Test that connected device can be disconnected */ +TEST_F(HearingAidTest, disconnect_when_connected) { + set_sample_database(1); + + ON_CALL(btm_interface, BTM_IsEncrypted(test_address, _)).WillByDefault(Return(true)); + EXPECT_CALL(*callbacks, OnConnectionState(ConnectionState::CONNECTED, test_address)).Times(1); + EXPECT_CALL(*callbacks, OnDeviceAvailable(_, _, test_address)); + HearingAid::Connect(test_address); + + /* First call from HearingAid:Disconnect. Second call from OnGattDisconnected*/ + EXPECT_CALL(*callbacks, OnConnectionState(ConnectionState::DISCONNECTED, test_address)).Times(2); + EXPECT_CALL(gatt_interface, Close(_)).Times(2); + HearingAid::Disconnect(test_address); +} + +} // namespace +} // namespace internal +} // namespace hearing_aid +} // namespace bluetooth diff --git a/system/bta/hh/bta_hh_le.cc b/system/bta/hh/bta_hh_le.cc index 6dc6365562..9cbd8569ab 100644 --- a/system/bta/hh/bta_hh_le.cc +++ b/system/bta/hh/bta_hh_le.cc @@ -925,14 +925,8 @@ static void bta_hh_le_dis_cback(const RawAddress& addr, tDIS_VALUE* p_dis_value) p_cb->dscp_info.version = p_dis_value->pnp_id.product_version; } - /* TODO(b/367910199): un-serialize once multiservice HoGP is implemented */ - if (com::android::bluetooth::flags::serialize_hogp_and_dis()) { - Uuid pri_srvc = Uuid::From16Bit(UUID_SERVCLASS_LE_HID); - BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, pri_srvc); - return; - } - - bta_hh_le_open_cmpl(p_cb); + Uuid pri_srvc = Uuid::From16Bit(UUID_SERVCLASS_LE_HID); + BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, pri_srvc); } /******************************************************************************* @@ -950,23 +944,16 @@ static void bta_hh_le_pri_service_discovery(tBTA_HH_DEV_CB* p_cb) { p_cb->disc_active |= (BTA_HH_LE_DISC_HIDS | BTA_HH_LE_DISC_DIS); - /* read DIS info */ + /* read DIS info. If failed, continue to discover HoGP services. */ if (!DIS_ReadDISInfo(p_cb->link_spec.addrt.bda, bta_hh_le_dis_cback, DIS_ATTR_PNP_ID_BIT)) { log::error("read DIS failed"); p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS; - } else { - /* TODO(b/367910199): un-serialize once multiservice HoGP is implemented */ - if (com::android::bluetooth::flags::serialize_hogp_and_dis()) { - log::debug("Waiting for DIS result before starting HoGP service discovery"); - return; - } + Uuid pri_srvc = Uuid::From16Bit(UUID_SERVCLASS_LE_HID); + BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, pri_srvc); + return; } - /* in parallel */ - /* start primary service discovery for HID service */ - Uuid pri_srvc = Uuid::From16Bit(UUID_SERVCLASS_LE_HID); - BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, pri_srvc); - return; + log::debug("Waiting for DIS result before starting HoGP service discovery"); } /******************************************************************************* @@ -1860,17 +1847,13 @@ static void read_report_cb(tCONN_ID conn_id, tGATT_STATUS status, uint16_t handl log::warn("Unexpected Read response, w4_evt={}", bta_hh_event_text(p_dev_cb->w4_evt)); return; } - if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT; - } + p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT; uint8_t hid_handle = p_dev_cb->hid_handle; const gatt::Characteristic* p_char = BTA_GATTC_GetCharacteristic(conn_id, handle); if (p_char == nullptr) { log::error("Unknown handle"); - if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - send_read_report_reply(hid_handle, BTA_HH_ERR, nullptr); - } + send_read_report_reply(hid_handle, BTA_HH_ERR, nullptr); return; } @@ -1884,16 +1867,10 @@ static void read_report_cb(tCONN_ID conn_id, tGATT_STATUS status, uint16_t handl break; default: log::error("Unexpected Read UUID: {}", p_char->uuid.ToString()); - if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - send_read_report_reply(hid_handle, BTA_HH_ERR, nullptr); - } + send_read_report_reply(hid_handle, BTA_HH_ERR, nullptr); return; } - if (!com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT; - } - if (status != GATT_SUCCESS) { send_read_report_reply(hid_handle, BTA_HH_ERR, nullptr); return; @@ -1937,9 +1914,7 @@ static void bta_hh_le_get_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type, uin if (p_rpt == nullptr) { log::error("no matching report"); - if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - send_read_report_reply(p_cb->hid_handle, BTA_HH_ERR, nullptr); - } + send_read_report_reply(p_cb->hid_handle, BTA_HH_ERR, nullptr); return; } @@ -1982,17 +1957,13 @@ static void write_report_cb(tCONN_ID conn_id, tGATT_STATUS status, uint16_t hand } log::verbose("w4_evt:{}", bta_hh_event_text(p_dev_cb->w4_evt)); - if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT; - } + p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT; uint8_t hid_handle = p_dev_cb->hid_handle; const gatt::Characteristic* p_char = BTA_GATTC_GetCharacteristic(conn_id, handle); if (p_char == nullptr) { log::error("Unknown characteristic handle: {}", handle); - if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - send_write_report_reply(hid_handle, BTA_HH_ERR, cb_evt); - } + send_write_report_reply(hid_handle, BTA_HH_ERR, cb_evt); return; } @@ -2000,17 +1971,10 @@ static void write_report_cb(tCONN_ID conn_id, tGATT_STATUS status, uint16_t hand if (uuid16 != GATT_UUID_HID_REPORT && uuid16 != GATT_UUID_HID_BT_KB_INPUT && uuid16 != GATT_UUID_HID_BT_MOUSE_INPUT && uuid16 != GATT_UUID_HID_BT_KB_OUTPUT) { log::error("Unexpected characteristic UUID: {}", p_char->uuid.ToString()); - if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - send_write_report_reply(hid_handle, BTA_HH_ERR, cb_evt); - } + send_write_report_reply(hid_handle, BTA_HH_ERR, cb_evt); return; } - /* Set Report finished */ - if (!com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT; - } - if (status == GATT_SUCCESS) { send_write_report_reply(hid_handle, BTA_HH_OK, cb_evt); } else { @@ -2033,9 +1997,7 @@ static void bta_hh_le_write_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type, B if (p_buf == NULL || p_buf->len == 0) { log::error("Illegal data"); - if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - send_write_report_reply(p_cb->hid_handle, BTA_HH_ERR, w4_evt); - } + send_write_report_reply(p_cb->hid_handle, BTA_HH_ERR, w4_evt); return; } @@ -2047,9 +2009,7 @@ static void bta_hh_le_write_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type, B p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode, r_type, rpt_id); if (p_rpt == NULL) { log::error("no matching report"); - if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - send_write_report_reply(p_cb->hid_handle, BTA_HH_ERR, w4_evt); - } + send_write_report_reply(p_cb->hid_handle, BTA_HH_ERR, w4_evt); osi_free(p_buf); return; } diff --git a/system/bta/include/OWNERS b/system/bta/include/OWNERS deleted file mode 100644 index 9dfb8422a1..0000000000 --- a/system/bta/include/OWNERS +++ /dev/null @@ -1 +0,0 @@ -per-file bta_hearing_aid_api.h=file:/OWNERS_hearingaid diff --git a/system/bta/le_audio/OWNERS b/system/bta/le_audio/OWNERS deleted file mode 100644 index a7d77894ba..0000000000 --- a/system/bta/le_audio/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_leaudio diff --git a/system/bta/le_audio/broadcaster/broadcaster_test.cc b/system/bta/le_audio/broadcaster/broadcaster_test.cc index a211a810ad..16177230d1 100644 --- a/system/bta/le_audio/broadcaster/broadcaster_test.cc +++ b/system/bta/le_audio/broadcaster/broadcaster_test.cc @@ -63,6 +63,8 @@ using testing::Test; using namespace bluetooth::le_audio; using namespace bluetooth; +using bluetooth::hci::testing::mock_controller_; + using bluetooth::le_audio::DsaMode; using bluetooth::le_audio::LeAudioCodecConfiguration; using bluetooth::le_audio::LeAudioSourceAudioHalClient; @@ -287,8 +289,8 @@ protected: init_message_loop_thread(); reset_mock_function_count_map(); - bluetooth::hci::testing::mock_controller_ = &mock_controller_; - ON_CALL(mock_controller_, SupportsBleIsochronousBroadcaster).WillByDefault(Return(true)); + mock_controller_ = std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); + ON_CALL(*mock_controller_, SupportsBleIsochronousBroadcaster).WillByDefault(Return(true)); iso_manager_ = bluetooth::hci::IsoManager::GetInstance(); ASSERT_NE(iso_manager_, nullptr); @@ -366,7 +368,7 @@ protected: ContentControlIdKeeper::GetInstance()->Stop(); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.release(); delete mock_audio_source_; iso_active_callback = nullptr; delete mock_audio_source_; @@ -436,7 +438,6 @@ protected: protected: MockLeAudioBroadcasterCallbacks mock_broadcaster_callbacks_; - bluetooth::hci::testing::MockControllerInterface mock_controller_; bluetooth::hci::IsoManager* iso_manager_; MockIsoManager* mock_iso_manager_; bluetooth::hci::iso_manager::BigCallbacks* big_callbacks_ = nullptr; diff --git a/system/bta/le_audio/codec_manager.cc b/system/bta/le_audio/codec_manager.cc index 9452218c5d..104d397833 100644 --- a/system/bta/le_audio/codec_manager.cc +++ b/system/bta/le_audio/codec_manager.cc @@ -733,11 +733,11 @@ public: bool AppendStreamMapExtension(const std::vector<struct types::cis>& cises, const stream_parameters& stream_params, uint8_t direction) { - // In the legacy mode we are already done - if (!IsUsingCodecExtensibility()) { - log::verbose("Codec Extensibility is disabled"); - return true; - } + /* Without the codec extensibility enabled, we still need the BT stack structure to + * have the valid extended codec configuration entries, as these are used for codec type + * matching. The extended data fields of the AIDL API data structures are filed + * right before the AIDL call, only if the codec extensibility is enabled + */ const std::string tag = types::BidirectionalPair<std::string>({.sink = "Sink", .source = "Source"}) diff --git a/system/bta/le_audio/codec_manager_test.cc b/system/bta/le_audio/codec_manager_test.cc index b8f79a609b..c69464b72e 100644 --- a/system/bta/le_audio/codec_manager_test.cc +++ b/system/bta/le_audio/codec_manager_test.cc @@ -300,10 +300,12 @@ public: bluetooth::legacy::hci::testing::SetMock(legacy_hci_mock_); - ON_CALL(controller_interface, SupportsBleIsochronousBroadcaster).WillByDefault(Return(true)); - ON_CALL(controller_interface, IsSupported(OpCode::CONFIGURE_DATA_PATH)) + bluetooth::hci::testing::mock_controller_ = + std::make_unique<NiceMock<bluetooth::hci::testing::MockControllerInterface>>(); + ON_CALL(*bluetooth::hci::testing::mock_controller_, SupportsBleIsochronousBroadcaster) + .WillByDefault(Return(true)); + ON_CALL(*bluetooth::hci::testing::mock_controller_, IsSupported(OpCode::CONFIGURE_DATA_PATH)) .WillByDefault(Return(true)); - bluetooth::hci::testing::mock_controller_ = &controller_interface; codec_manager = CodecManager::GetInstance(); @@ -311,9 +313,11 @@ public: RegisterSinkHalClientMock(); } - virtual void TearDown() override { codec_manager->Stop(); } + virtual void TearDown() override { + codec_manager->Stop(); + bluetooth::hci::testing::mock_controller_.release(); + } - NiceMock<bluetooth::hci::testing::MockControllerInterface> controller_interface; CodecManager* codec_manager; bluetooth::legacy::hci::testing::MockInterface legacy_hci_mock_; @@ -559,15 +563,16 @@ TEST_F(CodecManagerTestAdsp, testStreamConfigurationMono) { }; // Stream parameters + auto stream_map_entry_mono_bidir = + stream_map_info(97, codec_spec_conf::kLeAudioLocationMonoAudio, true); + stream_map_entry_mono_bidir.codec_config.id = kLeAudioCodecIdLc3; types::BidirectionalPair<stream_parameters> stream_params{ .sink = { .audio_channel_allocation = codec_spec_conf::kLeAudioLocationMonoAudio, .stream_config = { - .stream_map = {stream_map_info( - 97, codec_spec_conf::kLeAudioLocationMonoAudio, - true)}, + .stream_map = {stream_map_entry_mono_bidir}, .bits_per_sample = 16, .sampling_frequency_hz = 16000, .frame_duration_us = 10000, @@ -583,9 +588,7 @@ TEST_F(CodecManagerTestAdsp, testStreamConfigurationMono) { .audio_channel_allocation = codec_spec_conf::kLeAudioLocationMonoAudio, .stream_config = { - .stream_map = {stream_map_info( - 97, codec_spec_conf::kLeAudioLocationMonoAudio, - true)}, + .stream_map = {stream_map_entry_mono_bidir}, .bits_per_sample = 16, .sampling_frequency_hz = 16000, .frame_duration_us = 10000, @@ -628,6 +631,7 @@ TEST_F(CodecManagerTestAdsp, testStreamConfigurationMono) { ASSERT_EQ(codec_spec_conf::kLeAudioLocationMonoAudio, info.audio_channel_allocation); // The connected should be active ASSERT_TRUE(info.is_stream_active); + ASSERT_EQ(info.codec_config.id.coding_format, kLeAudioCodecIdLc3.coding_format); } else { ASSERT_EQ(97, info.stream_handle); diff --git a/system/bta/le_audio/devices_test.cc b/system/bta/le_audio/devices_test.cc index adc90e5213..cd711065c4 100644 --- a/system/bta/le_audio/devices_test.cc +++ b/system/bta/le_audio/devices_test.cc @@ -514,7 +514,9 @@ protected: desired_group_size_ = -1; bluetooth::manager::SetMockBtmInterface(&btm_interface_); - bluetooth::hci::testing::mock_controller_ = &controller_interface_; + + bluetooth::hci::testing::mock_controller_ = + std::make_unique<NiceMock<bluetooth::hci::testing::MockControllerInterface>>(); auto codec_location = ::bluetooth::le_audio::types::CodecLocation::HOST; bluetooth::le_audio::AudioSetConfigurationProvider::Initialize(codec_location); @@ -740,6 +742,8 @@ protected: if (codec_manager_) { codec_manager_->Stop(); } + + bluetooth::hci::testing::mock_controller_.reset(); } LeAudioDevice* AddTestDevice(int snk_ase_num, int src_ase_num, int snk_ase_num_cached = 0, @@ -1417,7 +1421,6 @@ protected: LeAudioDeviceGroup* group_ = nullptr; bluetooth::manager::MockBtmInterface btm_interface_; MockCsisClient mock_csis_client_module_; - NiceMock<bluetooth::hci::testing::MockControllerInterface> controller_interface_; bluetooth::le_audio::CodecManager* codec_manager_; MockCodecManager* mock_codec_manager_; diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc index a3c52dc9e6..02104518d2 100644 --- a/system/bta/le_audio/le_audio_client_test.cc +++ b/system/bta/le_audio/le_audio_client_test.cc @@ -1477,11 +1477,13 @@ protected: init_message_loop_thread(); reset_mock_function_count_map(); - ON_CALL(controller_, SupportsBleConnectedIsochronousStreamCentral).WillByDefault(Return(true)); - ON_CALL(controller_, SupportsBleConnectedIsochronousStreamPeripheral) + hci::testing::mock_controller_ = + std::make_unique<NiceMock<bluetooth::hci::testing::MockControllerInterface>>(); + ON_CALL(*hci::testing::mock_controller_, SupportsBleConnectedIsochronousStreamCentral) .WillByDefault(Return(true)); - ON_CALL(controller_, SupportsBle2mPhy).WillByDefault(Return(true)); - bluetooth::hci::testing::mock_controller_ = &controller_; + ON_CALL(*hci::testing::mock_controller_, SupportsBleConnectedIsochronousStreamPeripheral) + .WillByDefault(Return(true)); + ON_CALL(*hci::testing::mock_controller_, SupportsBle2mPhy).WillByDefault(Return(true)); bluetooth::manager::SetMockBtmInterface(&mock_btm_interface_); gatt::SetMockBtaGattInterface(&mock_gatt_interface_); gatt::SetMockBtaGattQueue(&mock_gatt_queue_); @@ -1595,7 +1597,7 @@ protected: } iso_manager_->Stop(); - bluetooth::hci::testing::mock_controller_ = nullptr; + hci::testing::mock_controller_.reset(); } protected: @@ -2761,7 +2763,6 @@ protected: /* Audio track metadata */ char* test_tags_ptr_ = nullptr; - NiceMock<bluetooth::hci::testing::MockControllerInterface> controller_; }; class UnicastTest : public UnicastTestNoInit { diff --git a/system/bta/le_audio/metrics_collector.cc b/system/bta/le_audio/metrics_collector.cc index a4fb4a353d..24da2e085c 100644 --- a/system/bta/le_audio/metrics_collector.cc +++ b/system/bta/le_audio/metrics_collector.cc @@ -25,9 +25,9 @@ #include <unordered_map> #include <vector> -#include "common/metrics.h" #include "hardware/bt_le_audio.h" #include "le_audio_types.h" +#include "os/metrics.h" #include "types/raw_address.h" namespace bluetooth::le_audio { @@ -199,7 +199,7 @@ public: device_address[i] = device_metric->address_; } - bluetooth::common::LogLeAudioConnectionSessionReported( + bluetooth::os::LogMetricLeAudioConnectionSessionReported( group_size_, group_id_, connection_duration_nanos, device_connecting_offset_nanos, device_connected_offset_nanos, device_connection_duration_nanos, device_connection_statuses, device_disconnection_statuses, device_address, @@ -278,7 +278,7 @@ void MetricsCollector::OnBroadcastStateChanged(bool started) { broadcast_beginning_timepoint_ = std::chrono::high_resolution_clock::now(); } else { auto broadcast_ending_timepoint_ = std::chrono::high_resolution_clock::now(); - bluetooth::common::LogLeAudioBroadcastSessionReported( + bluetooth::os::LogMetricLeAudioBroadcastSessionReported( get_timedelta_nanos(broadcast_beginning_timepoint_, broadcast_ending_timepoint_)); broadcast_beginning_timepoint_ = kInvalidTimePoint; } diff --git a/system/bta/le_audio/metrics_collector_test.cc b/system/bta/le_audio/metrics_collector_test.cc index c94db90ad6..199199bf8a 100644 --- a/system/bta/le_audio/metrics_collector_test.cc +++ b/system/bta/le_audio/metrics_collector_test.cc @@ -23,7 +23,7 @@ #include <cstdint> #include <vector> -#include "common/metrics.h" +#include "os/metrics.h" #include "types/raw_address.h" using testing::_; @@ -57,9 +57,9 @@ std::vector<int64_t> last_streaming_duration_nanos; std::vector<int32_t> last_streaming_context_type; namespace bluetooth { -namespace common { +namespace os { -void LogLeAudioConnectionSessionReported( +void LogMetricLeAudioConnectionSessionReported( int32_t group_size, int32_t group_metric_id, int64_t connection_duration_nanos, const std::vector<int64_t>& device_connecting_offset_nanos, const std::vector<int64_t>& device_connected_offset_nanos, @@ -85,11 +85,11 @@ void LogLeAudioConnectionSessionReported( last_streaming_context_type = streaming_context_type; } -void LogLeAudioBroadcastSessionReported(int64_t duration_nanos) { +void LogMetricLeAudioBroadcastSessionReported(int64_t duration_nanos) { last_broadcast_duration_nanos = duration_nanos; } -} // namespace common +} // namespace os } // namespace bluetooth namespace bluetooth::le_audio { diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc index e5ce67cf9d..b3f20fba39 100644 --- a/system/bta/le_audio/state_machine.cc +++ b/system/bta/le_audio/state_machine.cc @@ -681,8 +681,16 @@ public: kLogHciEvent, group->group_id_, leAudioDevice->address_, kLogSetDataPathOp + "cis_h:" + loghex(conn_handle) + " STATUS=" + loghex(status)); + /* Find ASE and later update state for the given cis.*/ + auto ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState(CisState::CONNECTED, + DataPathState::CONFIGURING); + if (status) { - log::error("failed to setup data path"); + log::error("Failed to setup data path for {}, cis handle: {:#x}, error: {:#x}", + leAudioDevice->address_, conn_handle, status); + if (ase && ase->cis_conn_hdl == conn_handle) { + ase->data_path_state = DataPathState::IDLE; + } StopStream(group); return; @@ -696,10 +704,6 @@ public: return; } - /* Update state for the given cis.*/ - auto ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState(CisState::CONNECTED, - DataPathState::CONFIGURING); - if (!ase || ase->cis_conn_hdl != conn_handle) { log::error("Cannot find ase by handle {}", conn_handle); return; diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc index d17bfda188..e0860515fb 100644 --- a/system/bta/le_audio/state_machine_test.cc +++ b/system/bta/le_audio/state_machine_test.cc @@ -261,7 +261,9 @@ protected: bluetooth::manager::SetMockBtmInterface(&btm_interface); gatt::SetMockBtaGattInterface(&gatt_interface); gatt::SetMockBtaGattQueue(&gatt_queue); - bluetooth::hci::testing::mock_controller_ = &controller_; + + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); overwrite_cis_status_idx_ = 0; use_cis_retry_cnt_ = false; @@ -649,7 +651,7 @@ protected: cached_remote_qos_configuration_for_ase_.clear(); LeAudioGroupStateMachine::Cleanup(); ::bluetooth::le_audio::AudioSetConfigurationProvider::Cleanup(); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.release(); } std::shared_ptr<LeAudioDevice> PrepareConnectedDevice(uint8_t id, @@ -1714,7 +1716,6 @@ protected: std::vector<RawAddress> addresses_; std::map<uint8_t, std::unique_ptr<LeAudioDeviceGroup>> le_audio_device_groups_; bool group_create_command_disallowed_ = false; - bluetooth::hci::testing::MockControllerInterface controller_; }; class StateMachineTest : public StateMachineTestBase { diff --git a/system/bta/test/bta_ag_sco_test.cc b/system/bta/test/bta_ag_sco_test.cc index 16caac7665..a90198c54a 100644 --- a/system/bta/test/bta_ag_sco_test.cc +++ b/system/bta/test/bta_ag_sco_test.cc @@ -43,14 +43,14 @@ protected: this->codec = codec; return enh_esco_params_t{}; }; - bluetooth::hci::testing::mock_controller_ = &controller_; + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); } void TearDown() override { test::mock::device_esco_parameters::esco_parameters_for_codec = {}; - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); } esco_codec_t codec; - bluetooth::hci::testing::MockControllerInterface controller_; }; TEST_P(BtaAgScoParameterSelectionTest, create_sco_cvsd) { diff --git a/system/bta/test/bta_ag_test.cc b/system/bta/test/bta_ag_test.cc index 5fa3884669..2114f7e773 100644 --- a/system/bta/test/bta_ag_test.cc +++ b/system/bta/test/bta_ag_test.cc @@ -65,7 +65,8 @@ protected: void SetUp() override { reset_mock_function_count_map(); fake_osi_ = std::make_unique<test::fake::FakeOsi>(); - bluetooth::hci::testing::mock_controller_ = &controller_; + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); main_thread_start_up(); post_on_bt_main([]() { log::info("Main thread started up"); }); @@ -85,7 +86,7 @@ protected: bta_sys_deregister(BTA_ID_AG); post_on_bt_main([]() { log::info("Main thread shutting down"); }); main_thread_shut_down(); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); } std::unique_ptr<test::fake::FakeOsi> fake_osi_; @@ -93,7 +94,6 @@ protected: uint32_t tmp_num = 0xFFFF; RawAddress addr; esco_codec_t codec; - bluetooth::hci::testing::MockControllerInterface controller_; }; class BtaAgSwbTest : public BtaAgTest { diff --git a/system/bta/test/bta_dm_test.cc b/system/bta/test/bta_dm_test.cc index 90d41d5e6f..b49008b739 100644 --- a/system/bta/test/bta_dm_test.cc +++ b/system/bta/test/bta_dm_test.cc @@ -65,10 +65,10 @@ class BtaDmTest : public BtaWithContextTest { protected: void SetUp() override { BtaWithContextTest::SetUp(); - ON_CALL(controller_, LeRand).WillByDefault([](bluetooth::hci::LeRandCallback cb) { - cb(0x1234); - }); - bluetooth::hci::testing::mock_controller_ = &controller_; + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); + ON_CALL(*bluetooth::hci::testing::mock_controller_, LeRand) + .WillByDefault([](bluetooth::hci::LeRandCallback cb) { cb(0x1234); }); BTA_dm_init(); bluetooth::legacy::testing::bta_dm_init_cb(); @@ -82,9 +82,8 @@ protected: void TearDown() override { bluetooth::legacy::testing::bta_dm_deinit_cb(); BtaWithContextTest::TearDown(); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); } - bluetooth::hci::testing::MockControllerInterface controller_; }; class BtaDmCustomAlarmTest : public BtaDmTest { diff --git a/system/bta/test/bta_sdp_test.cc b/system/bta/test/bta_sdp_test.cc index 06e8ff86aa..77f1762cc0 100644 --- a/system/bta/test/bta_sdp_test.cc +++ b/system/bta/test/bta_sdp_test.cc @@ -30,17 +30,16 @@ class BtaSdpTest : public BtaWithHwOnTest { protected: void SetUp() override { BtaWithHwOnTest::SetUp(); - ON_CALL(controller_, LeRand).WillByDefault([](bluetooth::hci::LeRandCallback cb) { - cb(0x1234); - }); - bluetooth::hci::testing::mock_controller_ = &controller_; + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); + ON_CALL(*bluetooth::hci::testing::mock_controller_, LeRand) + .WillByDefault([](bluetooth::hci::LeRandCallback cb) { cb(0x1234); }); } void TearDown() override { BtaWithHwOnTest::TearDown(); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); } - bluetooth::hci::testing::MockControllerInterface controller_; }; class BtaSdpRegisteredTest : public BtaSdpTest { diff --git a/system/bta/test/bta_test_fixtures.h b/system/bta/test/bta_test_fixtures.h index c259d0b916..e41e64d496 100644 --- a/system/bta/test/bta_test_fixtures.h +++ b/system/bta/test/bta_test_fixtures.h @@ -60,7 +60,8 @@ protected: ASSERT_NE(get_btm_client_interface().lifecycle.btm_init, nullptr); ASSERT_NE(get_btm_client_interface().lifecycle.btm_free, nullptr); - bluetooth::hci::testing::mock_controller_ = &mock_controller_; + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); bluetooth::testing::stack::rnr::set_interface(&mock_stack_rnr_interface_); test::mock::stack_gatt_api::GATT_Register.body = @@ -85,12 +86,11 @@ protected: mock_btm_client_interface.eir.BTM_WriteEIR = {}; bluetooth::testing::stack::rnr::reset_interface(); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); BtaWithFakesTest::TearDown(); } - bluetooth::hci::testing::MockControllerInterface mock_controller_; bluetooth::testing::stack::rnr::Mock mock_stack_rnr_interface_; }; diff --git a/system/bta/test/common/btif_storage_mock.cc b/system/bta/test/common/btif_storage_mock.cc index 7e4a4e5118..f5eb38939e 100644 --- a/system/bta/test/common/btif_storage_mock.cc +++ b/system/bta/test/common/btif_storage_mock.cc @@ -19,6 +19,7 @@ #include <bluetooth/log.h> +#include "bta_hearing_aid_api.h" #include "btif/include/btif_profile_storage.h" #include "btif/include/btif_storage.h" @@ -134,3 +135,17 @@ bt_status_t btif_storage_get_remote_device_property(const RawAddress* address, log::assert_that(btif_storage_interface != nullptr, "Mock storage module not set!"); return btif_storage_interface->GetRemoteDeviceProperty(address, property); } + +/** Get the hearing aid device properties. */ +bool btif_storage_get_hearing_aid_prop(const RawAddress& address, uint8_t* capabilities, + uint64_t* hi_sync_id, uint16_t* render_delay, + uint16_t* preparation_delay, uint16_t* codecs) { + log::assert_that(btif_storage_interface != nullptr, "Mock storage module not set!"); + return btif_storage_interface->GetHearingAidProp(address, capabilities, hi_sync_id, render_delay, + preparation_delay, codecs); +} + +void btif_storage_add_hearing_aid(const HearingDevice& dev_info) { + log::assert_that(btif_storage_interface != nullptr, "Mock storage module not set!"); + return btif_storage_interface->AddHearingAid(&dev_info); +} diff --git a/system/bta/test/common/btif_storage_mock.h b/system/bta/test/common/btif_storage_mock.h index 8809643f70..25f9bbdde0 100644 --- a/system/bta/test/common/btif_storage_mock.h +++ b/system/bta/test/common/btif_storage_mock.h @@ -21,6 +21,8 @@ #include "include/hardware/bluetooth.h" #include "types/raw_address.h" +struct HearingDevice; + namespace bluetooth { namespace storage { @@ -50,6 +52,11 @@ public: virtual bt_status_t GetRemoteDeviceProperty(const RawAddress* address, bt_property_t* property) = 0; + virtual bool GetHearingAidProp(const RawAddress& address, uint8_t* capabilities, + uint64_t* hi_sync_id, uint16_t* render_delay, + uint16_t* preparation_delay, uint16_t* codecs) = 0; + virtual void AddHearingAid(const HearingDevice* dev_info) = 0; + virtual ~BtifStorageInterface() = default; }; @@ -88,6 +95,11 @@ public: MOCK_METHOD((void), RemoveLeaudioHas, (const RawAddress& address), (override)); MOCK_METHOD((bt_status_t), GetRemoteDeviceProperty, (const RawAddress* address, bt_property_t* property), (override)); + MOCK_METHOD((bool), GetHearingAidProp, + (const RawAddress& address, uint8_t* capabilities, uint64_t* hi_sync_id, + uint16_t* render_delay, uint16_t* preparation_delay, uint16_t* codecs), + (override)); + MOCK_METHOD((void), AddHearingAid, (const HearingDevice* dev_info), (override)); }; /** diff --git a/system/btcore/Android.bp b/system/btcore/Android.bp index 6a0350afcb..b02ead0f8d 100644 --- a/system/btcore/Android.bp +++ b/system/btcore/Android.bp @@ -20,10 +20,8 @@ cc_library_static { "packages/modules/Bluetooth/system/gd", ], srcs: [ - "src/device_class.cc", "src/module.cc", "src/osi_module.cc", - "src/property.cc", ], header_libs: ["libbluetooth_headers"], static_libs: [ @@ -50,41 +48,3 @@ cc_library_headers { ], min_sdk_version: "30", } - -// Note: It's good to get the tests compiled both for the host and the target so -// we get to test with both Bionic libc and glibc -// libbtcore unit tests for target and host -cc_test { - name: "net_test_btcore", - test_suites: ["general-tests"], - defaults: [ - "fluoride_defaults", - "mts_defaults", - ], - local_include_dirs: ["include"], - include_dirs: ["packages/modules/Bluetooth/system"], - srcs: [ - "test/device_class_test.cc", - "test/property_test.cc", - ], - shared_libs: [ - "libbase", - "liblog", - ], - static_libs: [ - "libbluetooth-types", - "libbluetooth_log", - "libbtcore", - "libchrome", - "libcom.android.sysprop.bluetooth.wrapped", - "libosi", - ], - host_supported: true, - test_options: { - unit_test: true, - }, - sanitize: { - address: true, - }, - header_libs: ["libbluetooth_headers"], -} diff --git a/system/btcore/BUILD.gn b/system/btcore/BUILD.gn index 76853554cf..abfbd328ee 100644 --- a/system/btcore/BUILD.gn +++ b/system/btcore/BUILD.gn @@ -16,11 +16,9 @@ static_library("btcore") { sources = [ - "src/device_class.cc", "src/hal_util.cc", "src/module.cc", "src/osi_module.cc", - "src/property.cc", ] include_dirs = [ @@ -33,35 +31,3 @@ static_library("btcore") { "//bt/system/log:log_defaults", ] } - -if (use.test) { - executable("net_test_btcore") { - sources = [ - "test/device_class_test.cc", - "test/property_test.cc", - ] - - include_dirs = [ - "include", - "//bt/system", - ] - - deps = [ - "//bt/system/btcore", - "//bt/system/osi", - "//bt/system/types", - ] - - configs += [ - "//bt/system:external_gtest_main", - "//bt/system:target_defaults", - "//bt/system/log:log_defaults", - ] - - libs = [ - "pthread", - "rt", - "dl", - ] - } -} diff --git a/system/btcore/fuzzer/Android.bp b/system/btcore/fuzzer/Android.bp deleted file mode 100644 index 07b8c28f89..0000000000 --- a/system/btcore/fuzzer/Android.bp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "system_bt_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["system_bt_license"], -} - -cc_defaults { - name: "btcore_fuzz_defaults", - shared_libs: [ - "libcrypto", - "libstatslog_bt", - ], - static_libs: [ - "libbase", - "libbluetooth-types", - "libbluetooth_crypto_toolbox", - "libbluetooth_log", - "libbt-common", - "libbtcore", - "libchrome", - "libcom.android.sysprop.bluetooth.wrapped", - "libevent", - "liblog", - "libmodpb64", - "libosi", - "libprotobuf-cpp-lite", - ], - include_dirs: [ - "packages/modules/Bluetooth/system", - ], - header_libs: [ - "libbluetooth_headers", - ], - fuzz_config: { - cc: ["android-bluetooth-security@google.com"], - componentid: 27441, - hotlists: [ - "4593311", - ], - description: "The fuzzer targets the APIs of libbtcore", - vector: "local_no_privileges_required", - service_privilege: "privileged", - users: "multi_user", - fuzzed_code_usage: "shipped", - }, -} - -cc_fuzz { - name: "btcore_device_class_fuzzer", - defaults: [ - "btcore_fuzz_defaults", - ], - srcs: [ - "btcore_device_class_fuzzer.cpp", - ], -} - -cc_fuzz { - name: "btcore_property_fuzzer", - defaults: [ - "btcore_fuzz_defaults", - ], - srcs: [ - "btcore_property_fuzzer.cpp", - ], - -} - -cc_fuzz { - name: "btcore_module_fuzzer", - enabled: false, - defaults: [ - "btcore_fuzz_defaults", - ], - srcs: [ - "btcore_module_fuzzer.cpp", - ], -} diff --git a/system/btcore/fuzzer/README.md b/system/btcore/fuzzer/README.md deleted file mode 100644 index cf770e4385..0000000000 --- a/system/btcore/fuzzer/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Fuzzers for libbtcore - -## Plugin Design Considerations -The fuzzer plugins for `libbtcore` are designed based on the understanding of the -source code and tries to achieve the following: - -##### Maximize code coverage -The configuration parameters are not hard-coded, but instead selected based on -incoming data. This ensures more code paths are reached by the fuzzers. - -Fuzzers assigns values to the following parameters to pass on to libbtcore: -1. Bluetooth Device Type (parameter name: `deviceType`) -2. Bluetooth Adapter Visibility Mode (parameter name: `mode`) -3. Bluetooth Address (parameter name: `btAddress`) -4. Bluetooth Device Class parameter (parameter name: `deviceClassT`) - -| Parameter| Valid Values| Configured Value| -|------------- |-------------| ----- | -| `deviceType` | 0.`BT_DEVICE_DEVTYPE_BREDR` 1.`BT_DEVICE_DEVTYPE_BLE` 2.`BT_DEVICE_DEVTYPE_DUAL` | Value obtained from FuzzedDataProvider | -| `mode` | 0.`BT_SCAN_MODE_NONE` 1.`BT_SCAN_MODE_CONNECTABLE` 2.`BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE` | Value obtained from FuzzedDataProvider | -| `btAddress` | Values inside array ranges from `0x0` to `0xFF` | Value obtained from FuzzedDataProvider | -| `deviceClassT` | Values inside array ranges from `0x0` to `0xFF` | Value obtained from FuzzedDataProvider | -This also ensures that the plugins are always deterministic for any given input. - -##### Maximize utilization of input data -The plugins feed the entire input data to the module. -This ensures that the plugins tolerates any kind of input (empty, huge, -malformed, etc) and doesn't `exit()` on any input and thereby increasing the -chance of identifying vulnerabilities. - -## Build - -This describes steps to build btcore_device_class_fuzzer, btcore_property_fuzzer and btcore_module_fuzzer binaries. - -### Android - -#### Steps to build -Build the fuzzer -``` - $ mm -j$(nproc) btcore_device_class_fuzzer - $ mm -j$(nproc) btcore_property_fuzzer - $ mm -j$(nproc) btcore_module_fuzzer -``` -### Steps to run - -To run on device -``` - $ adb sync data - $ adb shell /data/fuzz/arm64/btcore_device_class_fuzzer/btcore_device_class_fuzzer - $ adb shell /data/fuzz/arm64/btcore_property_fuzzer/btcore_property_fuzzer - $ adb shell /data/fuzz/arm64/btcore_module_fuzzer/btcore_module_fuzzer -``` - -## References: - * http://llvm.org/docs/LibFuzzer.html - * https://github.com/google/oss-fuzz diff --git a/system/btcore/fuzzer/btcore_device_class_fuzzer.cpp b/system/btcore/fuzzer/btcore_device_class_fuzzer.cpp deleted file mode 100644 index fef1e33370..0000000000 --- a/system/btcore/fuzzer/btcore_device_class_fuzzer.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 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. - * - */ - -#include <fuzzer/FuzzedDataProvider.h> - -#include "btcore/include/device_class.h" - -class BTCoreDeviceClassFuzzer { -public: - void process(const uint8_t* data, size_t size); - -private: - std::unique_ptr<FuzzedDataProvider> mFdp = nullptr; -}; - -void BTCoreDeviceClassFuzzer::process(const uint8_t* data, size_t size) { - mFdp = std::make_unique<FuzzedDataProvider>(data, size); - size_t dcStreamSize = sizeof(bt_device_class_t) * sizeof(uint8_t); - - std::vector<uint8_t> dcStreamSrc(dcStreamSize, 0x0); - mFdp->ConsumeData(dcStreamSrc.data(), dcStreamSize); - - bt_device_class_t deviceClass; - device_class_from_stream(&deviceClass, dcStreamSrc.data()); - - std::vector<uint8_t> dcStreamDst(dcStreamSize, 0x0); - (void)device_class_to_stream(&deviceClass, dcStreamDst.data(), dcStreamSize); - - device_class_set_limited(&deviceClass, mFdp->ConsumeBool()); - (void)device_class_get_limited(&deviceClass); - - int val = mFdp->ConsumeIntegral<int>(); - device_class_set_major_device(&deviceClass, val); - (void)device_class_get_major_device(&deviceClass); - - val = mFdp->ConsumeIntegral<int>(); - device_class_set_minor_device(&deviceClass, val); - (void)device_class_get_minor_device(&deviceClass); - - device_class_set_information(&deviceClass, mFdp->ConsumeBool()); - (void)device_class_get_information(&deviceClass); - - bt_device_class_t deviceClassCopy; - (void)device_class_copy(&deviceClassCopy, &deviceClass); - (void)device_class_equals(&deviceClass, &deviceClassCopy); - - val = mFdp->ConsumeIntegralInRange(1, INT_MAX); - device_class_from_int(&deviceClass, val); - (void)device_class_to_int(&deviceClass); -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - BTCoreDeviceClassFuzzer btCoreDeviceClassFuzzer; - btCoreDeviceClassFuzzer.process(data, size); - return 0; -} diff --git a/system/btcore/fuzzer/btcore_module_fuzzer.cpp b/system/btcore/fuzzer/btcore_module_fuzzer.cpp deleted file mode 100644 index adb21b724d..0000000000 --- a/system/btcore/fuzzer/btcore_module_fuzzer.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 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. - * - */ - -#include "btcore/include/hal_util.h" -#include "btcore/include/module.h" - -extern const module_t osi_module; - -extern "C" { -struct android_namespace_t* android_get_exported_namespace(const char*) { return nullptr; } -} - -class BTCoreModuleFuzzer { -public: - void process(); -}; - -void BTCoreModuleFuzzer::process() { - const bt_interface_t* interface; - (void)hal_util_load_bt_library(&interface); - module_management_start(); - module_init(&osi_module); - (void)module_start_up(&osi_module); - (void)get_module(osi_module.name); - module_shut_down(&osi_module); - module_clean_up(&osi_module); - module_management_stop(); -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t*, size_t) { - BTCoreModuleFuzzer btCoreModuleFuzzer; - btCoreModuleFuzzer.process(); - return 0; -} diff --git a/system/btcore/fuzzer/btcore_property_fuzzer.cpp b/system/btcore/fuzzer/btcore_property_fuzzer.cpp deleted file mode 100644 index eabcf505c3..0000000000 --- a/system/btcore/fuzzer/btcore_property_fuzzer.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 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. - * - */ - -#include <fuzzer/FuzzedDataProvider.h> - -#include "btcore/include/property.h" -#include "types/bluetooth/uuid.h" -#include "types/raw_address.h" - -using bluetooth::Uuid; - -constexpr int32_t kRandomStringLength = 256; - -class BTCorePropertyFuzzer { -public: - void process(const uint8_t* data, size_t size); - -private: - std::unique_ptr<FuzzedDataProvider> mFdp = nullptr; -}; - -void BTCorePropertyFuzzer::process(const uint8_t* data, size_t size) { - mFdp = std::make_unique<FuzzedDataProvider>(data, size); - uint8_t addr[RawAddress::kLength]; - mFdp->ConsumeData(addr, sizeof(uint8_t) * RawAddress::kLength); - RawAddress btAddress = {addr}; - bt_property_t* property = property_new_addr(&btAddress); - property_as_addr(property); - property_free(property); - - bt_device_class_t deviceClass = {{mFdp->ConsumeIntegral<uint8_t>(), - mFdp->ConsumeIntegral<uint8_t>(), - mFdp->ConsumeIntegral<uint8_t>()}}; - property = property_new_device_class(&deviceClass); - - const bt_device_class_t* pDeviceClass = property_as_device_class(property); - (void)device_class_to_int(pDeviceClass); - property_free(property); - - bt_device_type_t deviceType = (bt_device_type_t)(mFdp->ConsumeIntegral<uint32_t>()); - property = property_new_device_type(deviceType); - (void)property_as_device_type(property); - property_free(property); - - uint32_t timeout = mFdp->ConsumeIntegral<uint32_t>(); - property = property_new_discoverable_timeout(timeout); - (void)property_as_discoverable_timeout(property); - property_free(property); - - std::string name = mFdp->ConsumeRandomLengthString(kRandomStringLength); - property = property_new_name(name.c_str()); - (void)property_as_name(property); - property_free(property); - - int8_t rssi = mFdp->ConsumeIntegral<int8_t>(); - property = property_new_rssi(rssi); - (void)property_as_rssi(property); - property_free(property); - - size_t uuidSize = sizeof(uint8_t) * bluetooth::Uuid::kNumBytes128; - uint8_t uuid[bluetooth::Uuid::kNumBytes128]; - mFdp->ConsumeData(uuid, uuidSize); - Uuid uuidBE = Uuid::From128BitBE(uuid); - property = property_new_uuids(&uuidBE, 1); - size_t uuidCount; - (void)property_as_uuids(property, &uuidCount); - property_free(property); - - mFdp->ConsumeData(uuid, uuidSize); - Uuid uuidLE = Uuid::From128BitLE(uuid); - Uuid uuids[] = {uuidBE, uuidLE}; - bt_property_t* propertySrc = property_new_uuids(uuids, std::size(uuids)); - bt_property_t propertyDest; - (void)property_copy(&propertyDest, propertySrc); - property_free(propertySrc); -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - BTCorePropertyFuzzer btCorePropertyFuzzer; - btCorePropertyFuzzer.process(data, size); - return 0; -} diff --git a/system/btcore/include/device_class.h b/system/btcore/include/device_class.h deleted file mode 100644 index 6f56b119b0..0000000000 --- a/system/btcore/include/device_class.h +++ /dev/null @@ -1,95 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#pragma once - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -// Provides Class Of Device primitive as specified in the bluetooth spec. -// [Class Of Device] -// (https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband) - -// Device class may be defined in other structures. -// Only use defined methods to manipulate internals. -typedef struct bt_device_class_t { - uint8_t _[3]; // Do not access directly; use methods below. -} bt_device_class_t; - -// Copies the |data| class of device stream into device class |dc|. |dc| -// and |data| must not be NULL. -void device_class_from_stream(bt_device_class_t* dc, const uint8_t* data); - -// Serializes the device class |dc| to pointer argument |data| in big endian -// format. |len| must contain the buffer size of |data|. Returns the actual -// number of bytes copied into |data|. |dc| and |data| must not be NULL. -int device_class_to_stream(const bt_device_class_t* dc, uint8_t* data, size_t len); - -// Copies the |data| class of device integer into device class |dc|. |dc| -// must not be NULL. -void device_class_from_int(bt_device_class_t* dc, int data); - -// Returns the device class |dc| in integer format. |dc| must not be NULL. -int device_class_to_int(const bt_device_class_t* dc); - -// Compares and returns |true| if two device classes |p1| and |p2| are equal. -// False otherwise. -bool device_class_equals(const bt_device_class_t* p1, const bt_device_class_t* p2); - -// Copies and returns |true| if the device class was successfully copied from -// |p2| into |p1|. False otherwise. -bool device_class_copy(bt_device_class_t* dest, const bt_device_class_t* src); - -// Query, getters and setters for the major device class. |dc| must not be -// NULL. -int device_class_get_major_device(const bt_device_class_t* dc); -void device_class_set_major_device(bt_device_class_t* dc, int val); - -// Query, getters and setters for the minor device class. |dc| must not be NULL. -int device_class_get_minor_device(const bt_device_class_t* dc); -void device_class_set_minor_device(bt_device_class_t* dc, int val); - -// Query, getters and setters for the various major service class features. -// |dc| must not be NULL. -bool device_class_get_limited(const bt_device_class_t* dc); -void device_class_set_limited(bt_device_class_t* dc, bool set); - -bool device_class_get_positioning(const bt_device_class_t* dc); -void device_class_set_positioning(bt_device_class_t* dc, bool set); - -bool device_class_get_networking(const bt_device_class_t* dc); -void device_class_set_networking(bt_device_class_t* dc, bool set); - -bool device_class_get_rendering(const bt_device_class_t* dc); -void device_class_set_rendering(bt_device_class_t* dc, bool set); - -bool device_class_get_capturing(const bt_device_class_t* dc); -void device_class_set_capturing(bt_device_class_t* dc, bool set); - -bool device_class_get_object_transfer(const bt_device_class_t* dc); -void device_class_set_object_transfer(bt_device_class_t* dc, bool set); - -bool device_class_get_audio(const bt_device_class_t* dc); -void device_class_set_audio(bt_device_class_t* dc, bool set); - -bool device_class_get_telephony(const bt_device_class_t* dc); -void device_class_set_telephony(bt_device_class_t* dc, bool set); - -bool device_class_get_information(const bt_device_class_t* dc); -void device_class_set_information(bt_device_class_t* dc, bool set); diff --git a/system/btcore/include/device_features.h b/system/btcore/include/device_features.h deleted file mode 100644 index 13f8653635..0000000000 --- a/system/btcore/include/device_features.h +++ /dev/null @@ -1,27 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#pragma once - -#include <stdint.h> - -// Represents a page of device feature enabled/disabled bits returned -// by the local controller. See the bluetooth spec for bit indexes. -typedef struct { - uint8_t as_array[8]; -} bt_device_features_t; diff --git a/system/btcore/include/event_mask.h b/system/btcore/include/event_mask.h deleted file mode 100644 index f811c78c8e..0000000000 --- a/system/btcore/include/event_mask.h +++ /dev/null @@ -1,28 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#pragma once - -#include <stdint.h> - -// Represents a mask which can be used to tell the controller which -// HCI events the stack wishes to be informed about. See the bluetooth -// spec for more information on what each bit means. -typedef struct { - const uint8_t as_array[8]; -} bt_event_mask_t; diff --git a/system/btcore/include/iac.h b/system/btcore/include/iac.h deleted file mode 100644 index 39c830e54b..0000000000 --- a/system/btcore/include/iac.h +++ /dev/null @@ -1,28 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#pragma once - -#include <stdint.h> - -// Inquiry Access Code -// [Bluetooth Baseband] -// (https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband) -typedef struct { - uint8_t iac[3]; -} __attribute__((packed)) bt_inquiry_access_code_t; diff --git a/system/btcore/include/property.h b/system/btcore/include/property.h deleted file mode 100644 index f8e06150ad..0000000000 --- a/system/btcore/include/property.h +++ /dev/null @@ -1,76 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#pragma once - -#include <hardware/bluetooth.h> -#include <stdint.h> -#include <stdlib.h> - -#include "btcore/include/device_class.h" -#include "types/bluetooth/uuid.h" -#include "types/raw_address.h" - -// Copies an array of consecutive properties of |count| to a newly -// allocated array. |properties| must not be NULL. -bt_property_t* property_copy_array(const bt_property_t* properties, size_t count); - -// Copies |src| to |dest|. Returns the value of |dest|. -// |src| and |dest| must not be NULL. -bt_property_t* property_copy(bt_property_t* dest, const bt_property_t* src); - -// Returns true if the value of the two properties |p1| and |p2| are equal. -// |p1| and |p2| must not be NULL. -bool property_equals(const bt_property_t* p1, const bt_property_t* p2); - -// Property resource allocations. Caller is expected to free |property| -// using |property_free| or |property_free_array|. -// Parameter must not be NULL. A copy of the parameter is made and -// stored in the property. -bt_property_t* property_new_addr(const RawAddress* addr); -bt_property_t* property_new_device_class(const bt_device_class_t* dc); -bt_property_t* property_new_device_type(bt_device_type_t device_type); -bt_property_t* property_new_discoverable_timeout(const uint32_t timeout); -bt_property_t* property_new_name(const char* name); -bt_property_t* property_new_rssi(const int8_t rssi); -bt_property_t* property_new_uuids(const bluetooth::Uuid* uuid, size_t count); - -// Property resource frees both property and value. -void property_free(bt_property_t* property); -void property_free_array(bt_property_t* properties, size_t count); - -// Value check convenience methods. The contents of the property are -// checked for the respective validity and returns true, false otherwise. -// |property| must not be NULL. -bool property_is_addr(const bt_property_t* property); -bool property_is_device_class(const bt_property_t* property); -bool property_is_device_type(const bt_property_t* property); -bool property_is_discoverable_timeout(const bt_property_t* property); -bool property_is_name(const bt_property_t* property); -bool property_is_rssi(const bt_property_t* property); -bool property_is_uuids(const bt_property_t* property); - -// Value conversion convenience methods. The contents of the property are -// properly typed and returned to the caller. |property| must not be NULL. -const RawAddress* property_as_addr(const bt_property_t* property); -const bt_device_class_t* property_as_device_class(const bt_property_t* property); -bt_device_type_t property_as_device_type(const bt_property_t* property); -uint32_t property_as_discoverable_timeout(const bt_property_t* property); -const bt_bdname_t* property_as_name(const bt_property_t* property); -int8_t property_as_rssi(const bt_property_t* property); -const bluetooth::Uuid* property_as_uuids(const bt_property_t* property, size_t* count); diff --git a/system/btcore/include/version.h b/system/btcore/include/version.h deleted file mode 100644 index d7787c7409..0000000000 --- a/system/btcore/include/version.h +++ /dev/null @@ -1,29 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#pragma once - -#include <stdint.h> - -typedef struct { - uint8_t hci_version; - uint16_t hci_revision; - uint8_t lmp_version; - uint16_t manufacturer; - uint16_t lmp_subversion; -} bt_version_t; diff --git a/system/btcore/src/device_class.cc b/system/btcore/src/device_class.cc deleted file mode 100644 index 08d2ae191a..0000000000 --- a/system/btcore/src/device_class.cc +++ /dev/null @@ -1,167 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "btcore/include/device_class.h" - -#include <arpa/inet.h> -#include <bluetooth/log.h> -#include <endian.h> -#include <string.h> - -using namespace bluetooth; - -typedef struct _bt_device_class_t { - uint32_t unused : 2; // LSBs - uint32_t minor_device : 6; - uint32_t major_device : 5; - uint32_t major_service : 11; // MSBs -} __attribute__((__packed__)) _bt_device_class_t; - -// Convenience to interpret raw device class bytes. -#define DC(x) ((_bt_device_class_t*)(x)) - -// Ensure the internal device class implementation and public one -// have equal size. -static_assert(sizeof(_bt_device_class_t) == sizeof(bt_device_class_t), - "Internal and external device class implementation should have the same size"); - -// [Major Service Classes] -// (https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband) -enum { - DC_LIMITED_DISCOVERABLE_MODE = 0x0001, - DC_RESERVED14 = 0x0002, - DC_RESERVED15 = 0x0004, - DC_POSITIONING = 0x0008, - DC_NETWORKING = 0x0010, - DC_RENDERING = 0x0020, - DC_CAPTURING = 0x0040, - DC_OBJECT_TRANSFER = 0x0080, - DC_AUDIO = 0x0100, - DC_TELEPHONY = 0x0200, - DC_INFORMATION = 0x0400, -}; - -static bool device_class_get_major_service_(const bt_device_class_t* dc, int bitmask); -static void device_class_clr_major_service_(bt_device_class_t* dc, int bitmask); -static void device_class_set_major_service_(bt_device_class_t* dc, int bitmask); - -void device_class_from_stream(bt_device_class_t* dc, const uint8_t* data) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - log::assert_that(data != NULL, "assert failed: data != NULL"); - *dc = *(bt_device_class_t*)data; -} - -int device_class_to_stream(const bt_device_class_t* dc, uint8_t* data, size_t len) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - log::assert_that(data != NULL, "assert failed: data != NULL"); - log::assert_that(len >= sizeof(bt_device_class_t), - "assert failed: len >= sizeof(bt_device_class_t)"); - for (size_t i = 0; i < sizeof(bt_device_class_t); ++i) { - data[i] = dc->_[i]; - } - return sizeof(bt_device_class_t); -} - -void device_class_from_int(bt_device_class_t* dc, int data) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - log::assert_that(data != 0, "assert failed: data != 0"); - // Careful with endianess. - dc->_[0] = data & 0xff; - dc->_[1] = (data >> 8) & 0xff; - dc->_[2] = (data >> 16) & 0xff; -} - -int device_class_to_int(const bt_device_class_t* dc) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - // Careful with endianess. - int val = 0; - memcpy(&val, dc, sizeof(*dc)); - return static_cast<int>(le32toh(val) & 0xffffff); -} - -bool device_class_equals(const bt_device_class_t* p1, const bt_device_class_t* p2) { - log::assert_that(p1 != NULL, "assert failed: p1 != NULL"); - log::assert_that(p2 != NULL, "assert failed: p2 != NULL"); - return memcmp(p1, p2, sizeof(bt_device_class_t)) == 0; -} - -bool device_class_copy(bt_device_class_t* dest, const bt_device_class_t* src) { - log::assert_that(dest != NULL, "assert failed: dest != NULL"); - log::assert_that(src != NULL, "assert failed: src != NULL"); - return memcpy(dest, src, sizeof(bt_device_class_t)) == dest; -} - -int device_class_get_major_device(const bt_device_class_t* dc) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - return DC(dc)->major_device; -} - -void device_class_set_major_device(bt_device_class_t* dc, int val) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - DC(dc)->major_device = val; -} - -int device_class_get_minor_device(const bt_device_class_t* dc) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - return DC(dc)->minor_device; -} - -void device_class_set_minor_device(bt_device_class_t* dc, int val) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - DC(dc)->minor_device = val; -} - -bool device_class_get_information(const bt_device_class_t* dc) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - return device_class_get_major_service_(dc, DC_INFORMATION); -} - -void device_class_set_information(bt_device_class_t* dc, bool set) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - if (set) { - device_class_set_major_service_(dc, DC_INFORMATION); - } else { - device_class_clr_major_service_(dc, DC_INFORMATION); - } -} - -bool device_class_get_limited(const bt_device_class_t* dc) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - return device_class_get_major_service_(dc, DC_LIMITED_DISCOVERABLE_MODE); -} - -void device_class_set_limited(bt_device_class_t* dc, bool set) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - if (set) { - device_class_set_major_service_(dc, DC_LIMITED_DISCOVERABLE_MODE); - } else { - device_class_clr_major_service_(dc, DC_LIMITED_DISCOVERABLE_MODE); - } -} - -static bool device_class_get_major_service_(const bt_device_class_t* dc, int bitmask) { - return DC(dc)->major_service & bitmask; -} - -static void device_class_clr_major_service_(bt_device_class_t* dc, int bitmask) { - DC(dc)->major_service &= ~bitmask; -} - -static void device_class_set_major_service_(bt_device_class_t* dc, int bitmask) { - DC(dc)->major_service |= bitmask; -} diff --git a/system/btcore/src/property.cc b/system/btcore/src/property.cc deleted file mode 100644 index 0379229432..0000000000 --- a/system/btcore/src/property.cc +++ /dev/null @@ -1,217 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "btcore/include/property.h" - -#include <bluetooth/log.h> -#include <string.h> - -#include "btcore/include/device_class.h" -#include "osi/include/allocator.h" -#include "osi/include/compat.h" -#include "types/bluetooth/uuid.h" -#include "types/raw_address.h" - -using bluetooth::Uuid; -using namespace bluetooth; - -static bt_property_t* property_new_(void* val, size_t len, bt_property_type_t type); - -bt_property_t* property_copy_array(const bt_property_t* properties, size_t count) { - log::assert_that(properties != NULL, "assert failed: properties != NULL"); - bt_property_t* clone = static_cast<bt_property_t*>(osi_calloc(sizeof(bt_property_t) * count)); - - memcpy(&clone[0], &properties[0], sizeof(bt_property_t) * count); - for (size_t i = 0; i < count; ++i) { - clone[i].val = osi_calloc(clone[i].len); - memcpy(clone[i].val, properties[i].val, clone[i].len); - } - - return clone; -} - -bt_property_t* property_copy(bt_property_t* dest, const bt_property_t* src) { - log::assert_that(dest != NULL, "assert failed: dest != NULL"); - log::assert_that(src != NULL, "assert failed: src != NULL"); - return (bt_property_t*)memcpy(dest, src, sizeof(bt_property_t)); -} - -bool property_equals(const bt_property_t* p1, const bt_property_t* p2) { - // Two null properties are not the same. May need to revisit that - // decision when we have a test case that exercises that condition. - if (!p1 || !p2 || p1->type != p2->type) { - return false; - } - - // Although the Bluetooth name is a 249-byte array, the implementation - // treats it like a variable-length array with its size specified in the - // property's `len` field. We special-case the equivalence of BDNAME - // types here by truncating the larger, zero-padded name to its string - // length and comparing against the shorter name. - // - // Note: it may be the case that both strings are zero-padded but that - // hasn't come up yet so this implementation doesn't handle it. - if (p1->type == BT_PROPERTY_BDNAME && p1->len != p2->len) { - const bt_property_t *shorter = p1, *longer = p2; - if (p1->len > p2->len) { - shorter = p2; - longer = p1; - } - return strlen((const char*)longer->val) == (size_t)shorter->len && - !memcmp(longer->val, shorter->val, shorter->len); - } - - return p1->len == p2->len && !memcmp(p1->val, p2->val, p1->len); -} - -bt_property_t* property_new_addr(const RawAddress* addr) { - log::assert_that(addr != NULL, "assert failed: addr != NULL"); - return property_new_((void*)addr, sizeof(RawAddress), BT_PROPERTY_BDADDR); -} - -bt_property_t* property_new_device_class(const bt_device_class_t* dc) { - log::assert_that(dc != NULL, "assert failed: dc != NULL"); - return property_new_((void*)dc, sizeof(bt_device_class_t), BT_PROPERTY_CLASS_OF_DEVICE); -} - -bt_property_t* property_new_device_type(bt_device_type_t type) { - return property_new_((void*)&type, sizeof(bt_device_type_t), BT_PROPERTY_TYPE_OF_DEVICE); -} - -bt_property_t* property_new_discoverable_timeout(const uint32_t timeout) { - return property_new_((void*)&timeout, sizeof(uint32_t), BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT); -} - -bt_property_t* property_new_name(const char* name) { - log::assert_that(name != NULL, "assert failed: name != NULL"); - return property_new_((void*)name, sizeof(bt_bdname_t), BT_PROPERTY_BDNAME); -} - -bt_property_t* property_new_rssi(int8_t rssi) { - return property_new_((void*)&rssi, sizeof(int8_t), BT_PROPERTY_REMOTE_RSSI); -} - -bt_property_t* property_new_uuids(const Uuid* uuid, size_t count) { - log::assert_that(uuid != NULL, "assert failed: uuid != NULL"); - return property_new_((void*)uuid, sizeof(Uuid) * count, BT_PROPERTY_UUIDS); -} - -void property_free(bt_property_t* property) { property_free_array(property, 1); } - -void property_free_array(bt_property_t* properties, size_t count) { - if (properties == NULL) { - return; - } - - for (size_t i = 0; i < count; ++i) { - osi_free(properties[i].val); - } - - osi_free(properties); -} - -bool property_is_addr(const bt_property_t* property) { - log::assert_that(property != NULL, "assert failed: property != NULL"); - return property->type == BT_PROPERTY_BDADDR; -} - -bool property_is_device_class(const bt_property_t* property) { - log::assert_that(property != NULL, "assert failed: property != NULL"); - return property->type == BT_PROPERTY_CLASS_OF_DEVICE; -} - -bool property_is_device_type(const bt_property_t* property) { - log::assert_that(property != NULL, "assert failed: property != NULL"); - return property->type == BT_PROPERTY_TYPE_OF_DEVICE; -} - -bool property_is_discoverable_timeout(const bt_property_t* property) { - log::assert_that(property != NULL, "assert failed: property != NULL"); - return property->type == BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT; -} - -bool property_is_name(const bt_property_t* property) { - log::assert_that(property != NULL, "assert failed: property != NULL"); - return property->type == BT_PROPERTY_BDNAME; -} - -bool property_is_rssi(const bt_property_t* property) { - log::assert_that(property != NULL, "assert failed: property != NULL"); - return property->type == BT_PROPERTY_REMOTE_RSSI; -} - -bool property_is_uuids(const bt_property_t* property) { - log::assert_that(property != NULL, "assert failed: property != NULL"); - return property->type == BT_PROPERTY_UUIDS; -} - -// Convenience conversion methods to property values -const RawAddress* property_as_addr(const bt_property_t* property) { - log::assert_that(property_is_addr(property), "assert failed: property_is_addr(property)"); - return (const RawAddress*)property->val; -} - -const bt_device_class_t* property_as_device_class(const bt_property_t* property) { - log::assert_that(property_is_device_class(property), - "assert failed: property_is_device_class(property)"); - return (const bt_device_class_t*)property->val; -} - -bt_device_type_t property_as_device_type(const bt_property_t* property) { - log::assert_that(property_is_device_type(property), - "assert failed: property_is_device_type(property)"); - return *(const bt_device_type_t*)property->val; -} - -uint32_t property_as_discoverable_timeout(const bt_property_t* property) { - log::assert_that(property_is_discoverable_timeout(property), - "assert failed: property_is_discoverable_timeout(property)"); - return *(const uint32_t*)property->val; -} - -const bt_bdname_t* property_as_name(const bt_property_t* property) { - log::assert_that(property_is_name(property), "assert failed: property_is_name(property)"); - return (const bt_bdname_t*)property->val; -} - -int8_t property_as_rssi(const bt_property_t* property) { - log::assert_that(property_is_rssi(property), "assert failed: property_is_rssi(property)"); - return *(const int8_t*)property->val; -} - -const Uuid* property_as_uuids(const bt_property_t* property, size_t* count) { - log::assert_that(property_is_uuids(property), "assert failed: property_is_uuids(property)"); - *count = sizeof(Uuid) / property->len; - return (const Uuid*)property->val; -} - -static bt_property_t* property_new_(void* val, size_t len, bt_property_type_t type) { - bt_property_t* property = static_cast<bt_property_t*>(osi_calloc(sizeof(bt_property_t))); - - property->val = osi_calloc(len + 1); - if (type == BT_PROPERTY_BDNAME) { - osi_strlcpy((char*)property->val, (const char*)val, len); - } else { - memcpy(property->val, val, len); - } - - property->type = type; - property->len = len; - - return property; -} diff --git a/system/btcore/test/device_class_test.cc b/system/btcore/test/device_class_test.cc deleted file mode 100644 index ed5f9581f0..0000000000 --- a/system/btcore/test/device_class_test.cc +++ /dev/null @@ -1,224 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "btcore/include/device_class.h" - -#include <arpa/inet.h> -#include <gtest/gtest.h> - -static ::testing::AssertionResult check_bitfield(const char* m_expr, const char* n_expr, int m, - int n) { - if (m == n) { - return ::testing::AssertionSuccess(); - } - - std::stringstream ss; - - ss.str(""); - ss << std::showbase << std::hex << std::setw(8) << std::setfill('0') << m; - std::string expected_str = ss.str(); - - ss.str(""); - ss << std::showbase << std::hex << std::setw(8) << std::setfill('0') << n; - std::string actual_str = ss.str(); - - return ::testing::AssertionFailure() - << m_expr << " and " << n_expr << " ( " << expected_str << " vs " << actual_str << " )"; -} - -class DeviceClassTest : public ::testing::Test {}; - -TEST_F(DeviceClassTest, cod_sizeof) { - uint8_t dc_stream[] = {0x00, 0x00, 0x00, 0x00}; - bt_device_class_t dc0; - device_class_from_stream(&dc0, dc_stream); - EXPECT_EQ((size_t)3, sizeof(dc0)); -} - -TEST_F(DeviceClassTest, simple) { - uint8_t dc_stream[][sizeof(bt_device_class_t)] = { - {0x00, 0x00, 0x00}, {0xff, 0xff, 0xff}, {0xaa, 0x55, 0xaa}, - {0x01, 0x23, 0x45}, {0x20, 0x07, 0x14}, - }; - - for (size_t i = 0; i < sizeof(dc_stream) / sizeof(bt_device_class_t); i++) { - bt_device_class_t dc; - device_class_from_stream(&dc, (uint8_t*)&dc_stream[i]); - - uint8_t* to_stream = (uint8_t*)&dc; - EXPECT_PRED_FORMAT2(check_bitfield, (unsigned)dc_stream[i][0], to_stream[0]); - EXPECT_PRED_FORMAT2(check_bitfield, (unsigned)dc_stream[i][1], to_stream[1]); - EXPECT_PRED_FORMAT2(check_bitfield, (unsigned)dc_stream[i][2], to_stream[2]); - } -} - -TEST_F(DeviceClassTest, to_stream) { - { - bt_device_class_t dc; - - uint8_t dc_stream0[] = {0x00, 0x00, 0x00, 0xaa}; - device_class_from_stream(&dc, dc_stream0); - - uint8_t dc_stream1[] = {0x00, 0x00, 0x00, 0x00}; - int rc = device_class_to_stream(&dc, dc_stream1, sizeof(dc_stream1)); - EXPECT_EQ(3, rc); - - uint32_t val = 0; - memcpy(&val, &dc, sizeof(dc)); - EXPECT_PRED_FORMAT2(check_bitfield, 0x00000000, val); - - EXPECT_PRED_FORMAT2(check_bitfield, 0x00, dc_stream1[0]); - EXPECT_PRED_FORMAT2(check_bitfield, 0x00, dc_stream1[1]); - EXPECT_PRED_FORMAT2(check_bitfield, 0x00, dc_stream1[2]); - } - - { - uint8_t dc_stream0[] = {0xaa, 0x55, 0xaa, 0x55}; - uint8_t dc_stream1[] = {0x00, 0x00, 0x00, 0x00}; - - bt_device_class_t dc; - device_class_from_stream(&dc, dc_stream0); - - int rc = device_class_to_stream(&dc, dc_stream1, sizeof(dc_stream1)); - EXPECT_EQ(3, rc); - uint32_t val = 0; - memcpy(&val, &dc, sizeof(dc)); - EXPECT_PRED_FORMAT2(check_bitfield, 0x00aa55aa, val); - - EXPECT_PRED_FORMAT2(check_bitfield, 0xaa, dc_stream1[0]); - EXPECT_PRED_FORMAT2(check_bitfield, 0x55, dc_stream1[1]); - EXPECT_PRED_FORMAT2(check_bitfield, 0xaa, dc_stream1[2]); - } - - { - uint8_t dc_stream0[] = {0x01, 0x23, 0x45, 0x67}; - uint8_t dc_stream1[] = {0x00, 0x00, 0x00, 0x00}; - - bt_device_class_t dc; - device_class_from_stream(&dc, dc_stream0); - - int rc = device_class_to_stream(&dc, dc_stream1, sizeof(dc_stream1)); - EXPECT_EQ(3, rc); - uint32_t val = 0; - memcpy(&val, &dc, sizeof(dc)); - EXPECT_PRED_FORMAT2(check_bitfield, 0x452301, val); - - EXPECT_PRED_FORMAT2(check_bitfield, 0x01, dc_stream1[0]); - EXPECT_PRED_FORMAT2(check_bitfield, 0x23, dc_stream1[1]); - EXPECT_PRED_FORMAT2(check_bitfield, 0x45, dc_stream1[2]); - } -} - -TEST_F(DeviceClassTest, limited_discoverable_mode) { - uint8_t dc_stream[] = {0x00, 0x00, 0x00}; - bt_device_class_t dc; - device_class_from_stream(&dc, dc_stream); - uint32_t test = 0; - memcpy(&test, &dc, sizeof(dc)); - - EXPECT_FALSE(device_class_get_limited(&dc)); - EXPECT_EQ((unsigned)0x00000000, test); - - device_class_set_limited(&dc, true); - test = 0; - memcpy(&test, &dc, sizeof(dc)); - EXPECT_TRUE(device_class_get_limited(&dc)); - EXPECT_EQ((unsigned)0x00002000, test); - - device_class_set_limited(&dc, false); - test = 0; - memcpy(&test, &dc, sizeof(dc)); - EXPECT_FALSE(device_class_get_limited(&dc)); - EXPECT_EQ((unsigned)0x00000000, test); - - device_class_set_limited(&dc, true); - test = 0; - memcpy(&test, &dc, sizeof(dc)); - EXPECT_PRED_FORMAT2(check_bitfield, 0x00002000, test); - - device_class_set_limited(&dc, false); - test = 0; - memcpy(&test, &dc, sizeof(dc)); - EXPECT_PRED_FORMAT2(check_bitfield, 0x00000000, test); -} - -TEST_F(DeviceClassTest, equals) { - uint8_t dc_stream0[] = {0x00, 0x01, 0x02}; - uint8_t dc_stream1[] = {0x00, 0x02, 0x03}; - - bt_device_class_t dc0; - device_class_from_stream(&dc0, dc_stream0); - bt_device_class_t dc1; - device_class_from_stream(&dc1, dc_stream1); - EXPECT_FALSE(device_class_equals(&dc0, &dc1)); -} - -TEST_F(DeviceClassTest, copy) { - uint8_t dc_stream0[] = {0xaa, 0x55, 0x33}; - bt_device_class_t dc0; - device_class_from_stream(&dc0, dc_stream0); - bt_device_class_t dc1; - EXPECT_TRUE(device_class_copy(&dc1, &dc0)); - EXPECT_TRUE(device_class_equals(&dc0, &dc1)); -} - -TEST_F(DeviceClassTest, from_int) { - bt_device_class_t dc1; - int cod1 = 0x5a020c; // 5898764 - device_class_from_int(&dc1, cod1); - - uint8_t dc_stream[] = {0x0c, 0x02, 0x5a}; - bt_device_class_t dc2; - device_class_from_stream(&dc2, dc_stream); - EXPECT_TRUE(device_class_equals(&dc1, &dc2)); -} - -TEST_F(DeviceClassTest, to_int) { - bt_device_class_t dc1 = {{0x0c, 0x02, 0x5a}}; - int cod1 = device_class_to_int(&dc1); - - EXPECT_EQ(dc1._[0], 0x0c); - EXPECT_EQ(dc1._[1], 0x02); - EXPECT_EQ(dc1._[2], 0x5a); - - bt_device_class_t dc2; - uint8_t dc_stream[] = {0x0c, 0x02, 0x5a}; - device_class_from_stream(&dc2, dc_stream); - - EXPECT_EQ(dc2._[0], 0x0c); - EXPECT_EQ(dc2._[1], 0x02); - EXPECT_EQ(dc2._[2], 0x5a); - - int cod2 = device_class_to_int(&dc2); - EXPECT_EQ(cod1, cod2); - EXPECT_EQ(cod1, 0x5a020c); // 5898764 -} - -TEST_F(DeviceClassTest, endian) { - bt_device_class_t dc; - int cod1 = 0x200714; // 2098964 - device_class_from_int(&dc, cod1); - - EXPECT_EQ(dc._[0], 0x14); - EXPECT_EQ(dc._[1], 0x07); - EXPECT_EQ(dc._[2], 0x20); - - int cod2 = device_class_to_int(&dc); - EXPECT_EQ(cod1, cod2); - EXPECT_EQ(cod2, 0x200714); // 2098964 -} diff --git a/system/btcore/test/property_test.cc b/system/btcore/test/property_test.cc deleted file mode 100644 index 7477bca1a9..0000000000 --- a/system/btcore/test/property_test.cc +++ /dev/null @@ -1,269 +0,0 @@ -/****************************************************************************** - * - * Copyright 2014 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "btcore/include/property.h" - -#include <arpa/inet.h> -#include <gtest/gtest.h> - -#include "types/bluetooth/uuid.h" -#include "types/raw_address.h" - -using bluetooth::Uuid; - -class PropertyTest : public ::testing::Test {}; - -TEST_F(PropertyTest, addr) { - RawAddress addr0 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}}; - bt_property_t* property = property_new_addr(&addr0); - - EXPECT_EQ(addr0.address[0], ((uint8_t*)property->val)[0]); - EXPECT_EQ(addr0.address[1], ((uint8_t*)property->val)[1]); - EXPECT_EQ(addr0.address[2], ((uint8_t*)property->val)[2]); - EXPECT_EQ(addr0.address[3], ((uint8_t*)property->val)[3]); - EXPECT_EQ(addr0.address[4], ((uint8_t*)property->val)[4]); - EXPECT_EQ(addr0.address[5], ((uint8_t*)property->val)[5]); - EXPECT_EQ(BT_PROPERTY_BDADDR, property->type); - EXPECT_EQ((int)sizeof(RawAddress), property->len); - - const RawAddress* addr1 = property_as_addr(property); - EXPECT_EQ(addr0.address[0], addr1->address[0]); - - property_free(property); -} - -TEST_F(PropertyTest, device_class) { - bt_device_class_t dc0 = {{0x01, 0x23, 0x45}}; - bt_property_t* property = property_new_device_class(&dc0); - - EXPECT_EQ(dc0._[0], ((uint8_t*)property->val)[0]); - EXPECT_EQ(dc0._[1], ((uint8_t*)property->val)[1]); - EXPECT_EQ(dc0._[2], ((uint8_t*)property->val)[2]); - EXPECT_EQ(BT_PROPERTY_CLASS_OF_DEVICE, property->type); - EXPECT_EQ((int)sizeof(bt_device_class_t), property->len); - - const bt_device_class_t* dc1 = property_as_device_class(property); - int dc_int = device_class_to_int(dc1); - EXPECT_EQ(0x452301, dc_int); - - property_free(property); -} - -TEST_F(PropertyTest, device_type) { - bt_device_type_t dt0 = (bt_device_type_t)1; - bt_property_t* property = property_new_device_type(dt0); - - EXPECT_EQ((int)dt0, *(int*)property->val); - EXPECT_EQ(BT_PROPERTY_TYPE_OF_DEVICE, property->type); - EXPECT_EQ((int)sizeof(bt_device_type_t), property->len); - - bt_device_type_t dt1 = property_as_device_type(property); - EXPECT_EQ(1, (int)dt1); - - property_free(property); -} - -TEST_F(PropertyTest, discovery_timeout) { - uint32_t timeout0 = 12345; - bt_property_t* property = property_new_discoverable_timeout(timeout0); - - EXPECT_EQ(timeout0, *(uint32_t*)property->val); - EXPECT_EQ(BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT, property->type); - EXPECT_EQ((int)sizeof(uint32_t), property->len); - - uint32_t timeout1 = property_as_discoverable_timeout(property); - EXPECT_EQ(timeout0, timeout1); - - property_free(property); -} - -TEST_F(PropertyTest, name) { - const char* name0 = "My btcore name"; - bt_property_t* property = property_new_name(name0); - - EXPECT_EQ(0, strcmp((char*)name0, (char*)property->val)); - EXPECT_EQ(BT_PROPERTY_BDNAME, property->type); - EXPECT_EQ((int)sizeof(bt_bdname_t), property->len); - - const bt_bdname_t* name1 = property_as_name(property); - EXPECT_EQ(0, strcmp((char*)name0, (char*)name1->name)); - - property_free(property); -} - -TEST_F(PropertyTest, rssi) { - int8_t rssi0 = -56; - bt_property_t* property = property_new_rssi(rssi0); - - EXPECT_EQ(*(int8_t*)property->val, rssi0); - EXPECT_EQ(BT_PROPERTY_REMOTE_RSSI, property->type); - EXPECT_EQ((int)sizeof(int8_t), property->len); - - int8_t rss1 = property_as_rssi(property); - EXPECT_EQ(rssi0, rss1); - - property_free(property); -} - -TEST_F(PropertyTest, uuids) { - Uuid uuid0 = Uuid::From128BitBE({{ - 0x00, - 0x11, - 0x22, - 0x33, - 0x44, - 0x55, - 0x66, - 0x77, - 0x88, - 0x99, - 0xaa, - 0xbb, - 0xcc, - 0xdd, - 0xee, - 0xff, - }}); - bt_property_t* property = property_new_uuids(&uuid0, 1); - - EXPECT_EQ(0, memcmp(uuid0.To128BitBE().data(), property->val, sizeof(Uuid))); - EXPECT_EQ(BT_PROPERTY_UUIDS, property->type); - EXPECT_EQ((int)sizeof(Uuid), property->len); - - size_t uuid_cnt1; - const Uuid* uuid1 = property_as_uuids(property, &uuid_cnt1); - EXPECT_EQ(uuid0, *uuid1); - - property_free(property); -} - -TEST_F(PropertyTest, copy) { - { - Uuid uuids[] = { - Uuid::From128BitBE({{ - 0x00, - 0x11, - 0x22, - 0x33, - 0x44, - 0x55, - 0x66, - 0x77, - 0x88, - 0x99, - 0xaa, - 0xbb, - 0xcc, - 0xdd, - 0xee, - 0xff, - }}), - Uuid::From128BitBE({{ - 0xf0, - 0xe1, - 0xd2, - 0xc3, - 0xf4, - 0xe5, - 0xd6, - 0xc7, - 0xf8, - 0xe9, - 0xda, - 0xcb, - 0xfc, - 0xed, - 0xde, - 0xcf, - }}), - }; - - bt_property_t* property0 = property_new_uuids(uuids, sizeof(uuids) / sizeof(Uuid)); - - bt_property_t property1; - property_copy(&property1, property0); - EXPECT_TRUE(property_equals(property0, &property1)); - - property_free(property0); - } -} - -TEST_F(PropertyTest, equals) { - { - RawAddress addr0 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}}; - bt_property_t* property0 = property_new_addr(&addr0); - - bt_device_class_t dc0 = {{0x01, 0x23, 0x45}}; - bt_property_t* property1 = property_new_device_class(&dc0); - - EXPECT_FALSE(property_equals(property0, property1)); - - property_free(property0); - property_free(property1); - } - - { - RawAddress addr = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}}; - bt_property_t* property0 = property_new_addr(&addr); - bt_property_t* property1 = property_new_addr(&addr); - - EXPECT_TRUE(property_equals(property0, property1)); - - property_free(property0); - property_free(property1); - } - - { - RawAddress addr0 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}}; - bt_property_t* property0 = property_new_addr(&addr0); - - RawAddress addr1 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0xff}}; - bt_property_t* property1 = property_new_addr(&addr1); - - EXPECT_FALSE(property_equals(property0, property1)); - - property_free(property0); - property_free(property1); - } - - { - const char* name0 = "My btcore name"; - bt_property_t* property0 = property_new_name(name0); - - const char* name1 = "My btcore name"; - bt_property_t* property1 = property_new_name(name1); - - EXPECT_TRUE(property_equals(property0, property1)); - - property_free(property0); - property_free(property1); - } - - { - const char* name0 = "My btcore name"; - bt_property_t* property0 = property_new_name(name0); - - const char* name1 = "My btcore name "; - bt_property_t* property1 = property_new_name(name1); - - EXPECT_FALSE(property_equals(property0, property1)); - - property_free(property0); - property_free(property1); - } -} diff --git a/system/btif/Android.bp b/system/btif/Android.bp index 0eb097dca7..82544f36ba 100644 --- a/system/btif/Android.bp +++ b/system/btif/Android.bp @@ -122,7 +122,6 @@ cc_library_static { "src/btif_keystore.cc", "src/btif_le_audio.cc", "src/btif_le_audio_broadcaster.cc", - "src/btif_metrics_logging.cc", "src/btif_pan.cc", "src/btif_profile_queue.cc", "src/btif_profile_queue.cc", diff --git a/system/btif/BUILD.gn b/system/btif/BUILD.gn index ea6a0f6fbc..9def60989b 100644 --- a/system/btif/BUILD.gn +++ b/system/btif/BUILD.gn @@ -64,7 +64,6 @@ static_library("btif") { "src/btif_jni_task.cc", "src/btif_keystore.cc", "src/btif_le_audio.cc", - "src/btif_metrics_logging.cc", "src/btif_pan.cc", "src/btif_profile_queue.cc", "src/btif_profile_storage.cc", diff --git a/system/btif/include/btif_metrics_logging.h b/system/btif/include/btif_metrics_logging.h deleted file mode 100644 index 94f7a66b79..0000000000 --- a/system/btif/include/btif_metrics_logging.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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 - -#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h> -#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h> - -#include "main/shim/metric_id_api.h" -#include "types/raw_address.h" - -void log_a2dp_audio_underrun_event(const RawAddress& address, uint64_t encoding_interval_millis, - int num_missing_pcm_bytes); - -void log_a2dp_audio_overrun_event(const RawAddress& address, uint64_t encoding_interval_millis, - int num_dropped_buffers, int num_dropped_encoded_frames, - int num_dropped_encoded_bytes); - -void log_a2dp_playback_event(const RawAddress& address, int playback_state, int audio_coding_mode); - -void log_a2dp_session_metrics_event(const RawAddress& address, int64_t audio_duration_ms, - int media_timer_min_ms, int media_timer_max_ms, - int media_timer_avg_ms, int total_scheduling_count, - int buffer_overruns_max_count, int buffer_overruns_total, - float buffer_underruns_average, int buffer_underruns_count, - int64_t codec_index, bool is_a2dp_offload); - -void log_read_rssi_result(const RawAddress& address, uint16_t handle, uint32_t cmd_status, - int8_t rssi); - -void log_read_failed_contact_counter_result(const RawAddress& address, uint16_t handle, - uint32_t cmd_status, int32_t failed_contact_counter); - -void log_read_tx_power_level_result(const RawAddress& address, uint16_t handle, uint32_t cmd_status, - int32_t transmit_power_level); - -void log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum key, int64_t value); - -void log_socket_connection_state(const RawAddress& address, int port, int type, - android::bluetooth::SocketConnectionstateEnum connection_state, - int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port, - android::bluetooth::SocketRoleEnum socket_role, - uint64_t connection_duration_ms, - android::bluetooth::SocketErrorEnum error_code, - bool is_hardware_offload); - -bool init_metric_id_allocator(const std::unordered_map<RawAddress, int>& paired_device_map, - bluetooth::shim::CallbackLegacy save_id_callback, - bluetooth::shim::CallbackLegacy forget_device_callback); - -bool close_metric_id_allocator(); - -int allocate_metric_id_from_metric_id_allocator(const RawAddress&); - -int save_metric_id_from_metric_id_allocator(const RawAddress&); - -void forget_device_from_metric_id_allocator(const RawAddress&); - -bool is_valid_id_from_metric_id_allocator(const int id); diff --git a/system/btif/src/OWNERS b/system/btif/src/OWNERS deleted file mode 100644 index e495e167d4..0000000000 --- a/system/btif/src/OWNERS +++ /dev/null @@ -1 +0,0 @@ -per-file btif_hearing_aid.cc=file:/OWNERS_hearingaid diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc index 5741b05c4f..9badbc9ab6 100644 --- a/system/btif/src/bluetooth.cc +++ b/system/btif/src/bluetooth.cc @@ -71,7 +71,6 @@ #include "btif/include/btif_hh.h" #include "btif/include/btif_keystore.h" #include "btif/include/btif_le_audio.h" -#include "btif/include/btif_metrics_logging.h" #include "btif/include/btif_pan.h" #include "btif/include/btif_profile_storage.h" #include "btif/include/btif_rc.h" @@ -99,6 +98,7 @@ #include "hardware/bt_vc.h" #include "internal_include/bt_target.h" #include "main/shim/dumpsys.h" +#include "main/shim/metric_id_api.h" #include "os/parameter_provider.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" @@ -1099,7 +1099,7 @@ static std::string obfuscate_address(const RawAddress& address) { } static int get_metric_id(const RawAddress& address) { - return allocate_metric_id_from_metric_id_allocator(address); + return bluetooth::shim::AllocateIdFromMetricIdAllocator(address); } static int set_dynamic_audio_buffer_size(int codec, int size) { diff --git a/system/btif/src/btif_a2dp_source.cc b/system/btif/src/btif_a2dp_source.cc index bf4c00c0d5..5bf2ef0d87 100644 --- a/system/btif/src/btif_a2dp_source.cc +++ b/system/btif/src/btif_a2dp_source.cc @@ -46,13 +46,12 @@ #include "btif_av_co.h" #include "btif_common.h" #include "btif_hf.h" -#include "btif_metrics_logging.h" #include "btm_iso_api.h" #include "common/message_loop_thread.h" -#include "common/metrics.h" #include "common/repeating_timer.h" #include "common/time_util.h" #include "hardware/bt_av.h" +#include "main/shim/metrics_api.h" #include "osi/include/allocator.h" #include "osi/include/fixed_queue.h" #include "osi/include/wakelock.h" @@ -931,8 +930,9 @@ static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) { btif_a2dp_source_cb.stats.media_read_total_underflow_count++; btif_a2dp_source_cb.stats.media_read_last_underflow_us = bluetooth::common::time_get_os_boottime_us(); - log_a2dp_audio_underrun_event(btif_av_source_active_peer(), - btif_a2dp_source_cb.encoder_interval_ms, len - bytes_read); + bluetooth::shim::LogMetricA2dpAudioUnderrunEvent(btif_av_source_active_peer(), + btif_a2dp_source_cb.encoder_interval_ms, + len - bytes_read); } return bytes_read; @@ -984,9 +984,9 @@ static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n, osi_free(p_data); } } - log_a2dp_audio_overrun_event(btif_av_source_active_peer(), - btif_a2dp_source_cb.encoder_interval_ms, drop_n, - num_dropped_encoded_frames, num_dropped_encoded_bytes); + bluetooth::shim::LogMetricA2dpAudioOverrunEvent( + btif_av_source_active_peer(), btif_a2dp_source_cb.encoder_interval_ms, drop_n, + num_dropped_encoded_frames, num_dropped_encoded_bytes); // Request additional debug info if we had to flush buffers RawAddress peer_bda = btif_av_source_active_peer(); @@ -1276,12 +1276,12 @@ static void btif_a2dp_source_update_metrics(void) { } if (metrics.audio_duration_ms != -1) { - log_a2dp_session_metrics_event(btif_av_source_active_peer(), metrics.audio_duration_ms, - metrics.media_timer_min_ms, metrics.media_timer_max_ms, - metrics.media_timer_avg_ms, metrics.total_scheduling_count, - metrics.buffer_overruns_max_count, metrics.buffer_overruns_total, - metrics.buffer_underruns_average, metrics.buffer_underruns_count, - metrics.codec_index, metrics.is_a2dp_offload); + bluetooth::shim::LogMetricA2dpSessionMetricsEvent( + btif_av_source_active_peer(), metrics.audio_duration_ms, metrics.media_timer_min_ms, + metrics.media_timer_max_ms, metrics.media_timer_avg_ms, metrics.total_scheduling_count, + metrics.buffer_overruns_max_count, metrics.buffer_overruns_total, + metrics.buffer_underruns_average, metrics.buffer_underruns_count, metrics.codec_index, + metrics.is_a2dp_offload); } } @@ -1301,8 +1301,8 @@ static void btm_read_rssi_cb(void* data) { return; } - log_read_rssi_result(result->rem_bda, bluetooth::common::kUnknownConnectionHandle, - result->hci_status, result->rssi); + bluetooth::shim::LogMetricReadRssiResult(result->rem_bda, bluetooth::os::kUnknownConnectionHandle, + result->hci_status, result->rssi); log::warn("device: {}, rssi: {}", result->rem_bda, result->rssi); } @@ -1318,9 +1318,9 @@ static void btm_read_failed_contact_counter_cb(void* data) { log::error("unable to read Failed Contact Counter (status {})", result->status); return; } - log_read_failed_contact_counter_result(result->rem_bda, - bluetooth::common::kUnknownConnectionHandle, - result->hci_status, result->failed_contact_counter); + bluetooth::shim::LogMetricReadFailedContactCounterResult( + result->rem_bda, bluetooth::os::kUnknownConnectionHandle, result->hci_status, + result->failed_contact_counter); log::warn("device: {}, Failed Contact Counter: {}", result->rem_bda, result->failed_contact_counter); @@ -1337,8 +1337,9 @@ static void btm_read_tx_power_cb(void* data) { log::error("unable to read Tx Power (status {})", result->status); return; } - log_read_tx_power_level_result(result->rem_bda, bluetooth::common::kUnknownConnectionHandle, - result->hci_status, result->tx_power); + bluetooth::shim::LogMetricReadTxPowerLevelResult(result->rem_bda, + bluetooth::os::kUnknownConnectionHandle, + result->hci_status, result->tx_power); log::warn("device: {}, Tx Power: {}", result->rem_bda, result->tx_power); } diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc index 101ebcc4a0..2ee3be4c88 100644 --- a/system/btif/src/btif_av.cc +++ b/system/btif/src/btif_av.cc @@ -52,18 +52,17 @@ #include "btif/include/btif_a2dp_source.h" #include "btif/include/btif_av_co.h" #include "btif/include/btif_common.h" -#include "btif/include/btif_metrics_logging.h" #include "btif/include/btif_profile_queue.h" #include "btif/include/btif_rc.h" #include "btif/include/btif_util.h" #include "btif/include/stack_manager_t.h" -#include "btif_metrics_logging.h" #include "common/state_machine.h" #include "device/include/device_iot_conf_defs.h" #include "device/include/device_iot_config.h" #include "hardware/bluetooth.h" #include "hardware/bt_av.h" #include "include/hardware/bt_rc.h" +#include "main/shim/metrics_api.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" @@ -1985,7 +1984,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data // incoming/outgoing connect/disconnect requests. log::warn("Peer {} : event={}: transitioning to Idle due to ACL Disconnect", peer_.PeerAddress(), BtifAvEvent::EventName(event)); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::A2DP_CONNECTION_ACL_DISCONNECTED, 1); btif_report_connection_state(peer_.PeerAddress(), BTAV_CONNECTION_STATE_DISCONNECTED, bt_status_t::BT_STATUS_FAIL, BTA_AV_FAIL, @@ -1998,7 +1997,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data case BTA_AV_REJECT_EVT: log::warn("Peer {} : event={} flags={}", peer_.PeerAddress(), BtifAvEvent::EventName(event), peer_.FlagsToString()); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::A2DP_CONNECTION_REJECT_EVT, 1); btif_report_connection_state(peer_.PeerAddress(), BTAV_CONNECTION_STATE_DISCONNECTED, bt_status_t::BT_STATUS_AUTH_REJECTED, BTA_AV_FAIL, @@ -2080,7 +2079,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data btif_report_connection_state(peer_.PeerAddress(), BTAV_CONNECTION_STATE_CONNECTED, bt_status_t::BT_STATUS_SUCCESS, BTA_AV_SUCCESS, peer_.IsSource() ? A2dpType::kSink : A2dpType::kSource); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::A2DP_CONNECTION_SUCCESS, 1); } else { if (btif_rc_is_connected_peer(peer_.PeerAddress())) { @@ -2099,7 +2098,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data btif_report_connection_state(peer_.PeerAddress(), BTAV_CONNECTION_STATE_DISCONNECTED, bt_status_t::BT_STATUS_FAIL, status, peer_.IsSource() ? A2dpType::kSink : A2dpType::kSource); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::A2DP_CONNECTION_FAILURE, 1); } @@ -2139,8 +2138,8 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data "Peer {} : event={} : device is already connecting, ignore Connect " "request", peer_.PeerAddress(), BtifAvEvent::EventName(event)); - log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum::A2DP_ALREADY_CONNECTING, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::A2DP_ALREADY_CONNECTING, 1); btif_queue_advance(); } break; @@ -2151,15 +2150,15 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data "Peer {} : event={} : device is already connecting, ignore incoming " "request", peer_.PeerAddress(), BtifAvEvent::EventName(event)); - log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum::A2DP_ALREADY_CONNECTING, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::A2DP_ALREADY_CONNECTING, 1); } break; case BTIF_AV_OFFLOAD_START_REQ_EVT: log::error("Peer {} : event={}: stream is not Opened", peer_.PeerAddress(), BtifAvEvent::EventName(event)); btif_a2dp_on_offload_started(peer_.PeerAddress(), BTA_AV_FAIL); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::A2DP_OFFLOAD_START_REQ_FAILURE, 1); break; @@ -2169,8 +2168,8 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data bt_status_t::BT_STATUS_FAIL, BTA_AV_FAIL, peer_.IsSource() ? A2dpType::kSink : A2dpType::kSource); peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle); - log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum::A2DP_CONNECTION_CLOSE, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::A2DP_CONNECTION_CLOSE, 1); DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(peer_.PeerAddress(), IOT_CONF_KEY_A2DP_CONN_FAIL_COUNT); if (peer_.SelfInitiatedConnection()) { btif_queue_advance(); @@ -2184,7 +2183,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data peer_.IsSource() ? A2dpType::kSink : A2dpType::kSource); peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle); DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(peer_.PeerAddress(), IOT_CONF_KEY_A2DP_CONN_FAIL_COUNT); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::A2DP_CONNECTION_DISCONNECTED, 1); if (peer_.SelfInitiatedConnection()) { btif_queue_advance(); @@ -2203,7 +2202,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data CHECK_RC_EVENT(event, reinterpret_cast<tBTA_AV*>(p_data)); default: - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::A2DP_CONNECTION_UNKNOWN_EVENT, 1); log::warn("Peer {} : Unhandled event={}", peer_.PeerAddress(), BtifAvEvent::EventName(event)); return false; @@ -2933,7 +2932,7 @@ static void btif_report_audio_state(const RawAddress& peer_address, btav_audio_s ? AudioCodingModeEnum::AUDIO_CODING_MODE_HARDWARE : AudioCodingModeEnum::AUDIO_CODING_MODE_SOFTWARE; - log_a2dp_playback_event(peer_address, playback_state, audio_coding_mode); + bluetooth::shim::LogMetricA2dpPlaybackEvent(peer_address, playback_state, audio_coding_mode); } void btif_av_report_source_codec_state( diff --git a/system/btif/src/btif_config.cc b/system/btif/src/btif_config.cc index 2ee8fe494d..9a0e50dea1 100644 --- a/system/btif/src/btif_config.cc +++ b/system/btif/src/btif_config.cc @@ -32,9 +32,10 @@ #include <unordered_map> #include "btif_keystore.h" -#include "btif_metrics_logging.h" #include "common/address_obfuscator.h" #include "main/shim/config.h" +#include "main/shim/metric_id_api.h" +#include "main/shim/metrics_api.h" #include "main/shim/shim.h" #include "storage/config_keys.h" #include "types/raw_address.h" @@ -111,7 +112,7 @@ static void init_metric_id_allocator() { // there is one metric id under this mac_address int id = 0; btif_config_get_int(addr_str, BTIF_STORAGE_KEY_METRICS_ID_KEY, &id); - if (is_valid_id_from_metric_id_allocator(id)) { + if (bluetooth::shim::IsValidIdFromMetricIdAllocator(id)) { paired_device_map[mac_address] = id; is_valid_id_found = true; } @@ -128,15 +129,15 @@ static void init_metric_id_allocator() { auto forget_device_callback = [](const RawAddress& address, const int /* id */) { return btif_config_remove(address.ToString(), BTIF_STORAGE_KEY_METRICS_ID_KEY); }; - if (!init_metric_id_allocator(paired_device_map, std::move(save_device_callback), - std::move(forget_device_callback))) { + if (!bluetooth::shim::InitMetricIdAllocator(paired_device_map, std::move(save_device_callback), + std::move(forget_device_callback))) { log::fatal("Failed to initialize MetricIdAllocator"); } // Add device_without_id for (auto& address : addresses_without_id) { - allocate_metric_id_from_metric_id_allocator(address); - save_metric_id_from_metric_id_allocator(address); + bluetooth::shim::AllocateIdFromMetricIdAllocator(address); + bluetooth::shim::SaveDeviceOnMetricIdAllocator(address); } } @@ -160,7 +161,7 @@ static future_t* clean_up(void) { "assert failed: bluetooth::shim::is_gd_stack_started_up()"); // GD storage module cleanup by itself std::unique_lock<std::recursive_mutex> lock(config_lock); - close_metric_id_allocator(); + bluetooth::shim::CloseMetricIdAllocator(); return future_new_immediate(FUTURE_SUCCESS); } diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc index 96ed5848b1..e10606b9dd 100644 --- a/system/btif/src/btif_dm.cc +++ b/system/btif/src/btif_dm.cc @@ -57,7 +57,6 @@ #include "btif_api.h" #include "btif_bqr.h" #include "btif_config.h" -#include "btif_metrics_logging.h" #include "btif_sdp.h" #include "btif_storage.h" #include "btif_util.h" @@ -72,6 +71,8 @@ #include "main/shim/entry.h" #include "main/shim/helpers.h" #include "main/shim/le_advertising_manager.h" +#include "main/shim/metric_id_api.h" +#include "main/shim/metrics_api.h" #include "main_thread.h" #include "metrics/bluetooth_event.h" #include "os/system_properties.h" @@ -582,11 +583,11 @@ static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr, state, pairing_cb.state, pairing_cb.sdp_attempts); if (state == BT_BOND_STATE_NONE) { - forget_device_from_metric_id_allocator(bd_addr); + bluetooth::shim::ForgetDeviceFromMetricIdAllocator(bd_addr); btif_config_remove_device(bd_addr.ToString()); } else if (state == BT_BOND_STATE_BONDED) { - allocate_metric_id_from_metric_id_allocator(bd_addr); - if (!save_metric_id_from_metric_id_allocator(bd_addr)) { + bluetooth::shim::AllocateIdFromMetricIdAllocator(bd_addr); + if (!bluetooth::shim::SaveDeviceOnMetricIdAllocator(bd_addr)) { log::error("Fail to save metric id for device:{}", bd_addr); } } @@ -1485,7 +1486,7 @@ static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* auto triple = eir_uuids_cache.try_emplace(bdaddr, std::set<Uuid>{}); uuid_iter = std::get<0>(triple); } - log::info("EIR UUIDs for {}:", bdaddr); + log::info("EIR UUIDs for {}", bdaddr); for (int i = 0; i < num_uuids; ++i) { Uuid uuid = Uuid::From16Bit(p_uuid16[i]); log::info("{}", uuid.ToString()); @@ -1608,7 +1609,7 @@ static void btif_on_service_discovery_results(RawAddress bd_addr, if (results_for_bonding_device) { // success for SDP bluetooth::metrics::LogSDPComplete(bd_addr, tBTA_STATUS::BTA_SUCCESS); - log::info("SDP finished for {}:", bd_addr); + log::info("SDP finished for {}", bd_addr); pairing_cb.sdp_over_classic = btif_dm_pairing_cb_t::ServiceDiscoveryState::FINISHED; } @@ -1619,7 +1620,7 @@ static void btif_on_service_discovery_results(RawAddress bd_addr, bt_property_t& le_prop = uuid_props[1]; if ((result == BTA_SUCCESS) && !uuids_param.empty()) { - log::info("New UUIDs for {}:", bd_addr); + log::info("New UUIDs for {}", bd_addr); for (const auto& uuid : uuids_param) { if (btif_should_ignore_uuid(uuid)) { continue; @@ -1757,7 +1758,7 @@ static void btif_on_gatt_results(RawAddress bd_addr, std::vector<bluetooth::Uuid bool lea_supported = is_le_audio_capable_during_service_discovery(bd_addr); if (is_transport_le) { - log::info("New GATT over LE UUIDs for {}:", bd_addr); + log::info("New GATT over LE UUIDs for {}", bd_addr); BTM_LogHistory(kBtmLogTag, bd_addr, "Discovered GATT services using LE transport"); if (btif_is_gatt_service_discovery_post_pairing(bd_addr)) { pairing_cb.gatt_over_le = btif_dm_pairing_cb_t::ServiceDiscoveryState::FINISHED; @@ -1785,7 +1786,7 @@ static void btif_on_gatt_results(RawAddress bd_addr, std::vector<bluetooth::Uuid } } } else { - log::debug("New GATT over SDP UUIDs for {}:", bd_addr); + log::debug("New GATT over SDP UUIDs for {}", bd_addr); BTM_LogHistory(kBtmLogTag, bd_addr, "Discovered GATT services using SDP transport"); } diff --git a/system/btif/src/btif_hf.cc b/system/btif/src/btif_hf.cc index 33fb900e07..178a1672e6 100644 --- a/system/btif/src/btif_hf.cc +++ b/system/btif/src/btif_hf.cc @@ -51,7 +51,6 @@ #include "bta/include/utl.h" #include "bta_ag_swb_aptx.h" #include "btif/include/btif_common.h" -#include "btif/include/btif_metrics_logging.h" #include "btif/include/btif_profile_queue.h" #include "btif/include/btif_util.h" #include "btm_api_types.h" @@ -390,7 +389,7 @@ static void btif_hf_upstreams_evt(uint16_t event, char* p_param) { p_data->open.status, btif_hf_cb[idx].connected_bda, p_data->open.bd_addr); bt_hf_callbacks->ConnectionStateCallback(BTHF_CONNECTION_STATE_DISCONNECTED, &(p_data->open.bd_addr)); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HFP_COLLISON_AT_AG_OPEN, 1); } break; @@ -412,7 +411,7 @@ static void btif_hf_upstreams_evt(uint16_t event, char* p_param) { btif_hf_cb[idx].connected_bda, p_data->open.bd_addr); bt_hf_callbacks->ConnectionStateCallback(BTHF_CONNECTION_STATE_DISCONNECTED, &(btif_hf_cb[idx].connected_bda)); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HFP_COLLISON_AT_CONNECTING, 1); reset_control_block(&btif_hf_cb[idx]); btif_queue_advance(); @@ -472,7 +471,7 @@ static void btif_hf_upstreams_evt(uint16_t event, char* p_param) { bt_hf_callbacks->ConnectionStateCallback(btif_hf_cb[idx].state, &connected_bda); } - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HFP_SELF_INITIATED_AG_FAILED, 1); btif_queue_advance(); if (btm_sec_is_a_bonded_dev(connected_bda)) { @@ -496,8 +495,8 @@ static void btif_hf_upstreams_evt(uint16_t event, char* p_param) { bt_hf_callbacks->ConnectionStateCallback(btif_hf_cb[idx].state, &connected_bda); if (failed_to_setup_slc) { log::error("failed to setup SLC for {}", connected_bda); - log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum::HFP_SLC_SETUP_FAILED, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HFP_SLC_SETUP_FAILED, 1); btif_queue_advance(); LogMetricHfpSlcFail(ToGdAddress(p_data->open.bd_addr)); DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(btif_hf_cb[idx].connected_bda, @@ -881,7 +880,7 @@ public: bt_status_t DisconnectAudio(RawAddress* bd_addr) override; bt_status_t isNoiseReductionSupported(RawAddress* bd_addr) override; bt_status_t isVoiceRecognitionSupported(RawAddress* bd_addr) override; - bt_status_t StartVoiceRecognition(RawAddress* bd_addr) override; + bt_status_t StartVoiceRecognition(RawAddress* bd_addr, bool sendResult) override; bt_status_t StopVoiceRecognition(RawAddress* bd_addr) override; bt_status_t VolumeControl(bthf_volume_type_t type, int volume, RawAddress* bd_addr) override; bt_status_t DeviceStatusNotification(bthf_network_state_t ntk_state, bthf_service_type_t svc_type, @@ -1024,7 +1023,7 @@ bt_status_t HeadsetInterface::isVoiceRecognitionSupported(RawAddress* bd_addr) { return BT_STATUS_SUCCESS; } -bt_status_t HeadsetInterface::StartVoiceRecognition(RawAddress* bd_addr) { +bt_status_t HeadsetInterface::StartVoiceRecognition(RawAddress* bd_addr, bool sendResult) { CHECK_BTHF_INIT(); int idx = btif_hf_idx_by_bdaddr(bd_addr); if ((idx < 0) || (idx >= BTA_AG_MAX_NUM_CLIENTS)) { @@ -1040,9 +1039,11 @@ bt_status_t HeadsetInterface::StartVoiceRecognition(RawAddress* bd_addr) { return BT_STATUS_UNSUPPORTED; } btif_hf_cb[idx].is_during_voice_recognition = true; - tBTA_AG_RES_DATA ag_res = {}; - ag_res.state = true; - BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, ag_res); + if (sendResult) { + tBTA_AG_RES_DATA ag_res = {}; + ag_res.state = true; + BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, ag_res); + } return BT_STATUS_SUCCESS; } diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc index 7288abe98c..28ed77113d 100644 --- a/system/btif/src/btif_hh.cc +++ b/system/btif/src/btif_hh.cc @@ -48,7 +48,6 @@ #include "btif/include/btif_common.h" #include "btif/include/btif_dm.h" #include "btif/include/btif_hd.h" -#include "btif/include/btif_metrics_logging.h" #include "btif/include/btif_profile_storage.h" #include "btif/include/btif_storage.h" #include "btif/include/btif_util.h" @@ -56,6 +55,7 @@ #include "include/hardware/bt_hh.h" #include "internal_include/bt_target.h" #include "main/shim/dumpsys.h" +#include "main/shim/metrics_api.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" #include "stack/include/bt_hdr.h" @@ -468,7 +468,7 @@ static void btif_hh_incoming_connection_timeout(void* data) { handle); } log::warn("Reject unexpected incoming HID Connection, device: {}", conn.link_spec); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_COUNT_INCOMING_CONNECTION_REJECTED, 1); btif_hh_device_t* p_dev = btif_hh_find_dev_by_link_spec(conn.link_spec); @@ -529,7 +529,7 @@ static bool hh_add_device(const tAclLinkSpec& link_spec, tBTA_HH_ATTR_MASK attr_ } log::error("Out of space to add device"); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_COUNT_MAX_ADDED_DEVICE_LIMIT_REACHED, 1); return false; } @@ -633,7 +633,7 @@ static void hh_open_handler(tBTA_HH_CONN& conn) { log::warn("Reject Incoming HID Connection, device: {}, state: {}", conn.link_spec, bthh_connection_state_text(dev_status)); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_COUNT_INCOMING_CONNECTION_REJECTED, 1); if (p_dev != nullptr) { @@ -749,9 +749,7 @@ static void hh_get_rpt_handler(tBTA_HH_HSDATA& hs_data) { HAL_CBACK(bt_hh_callbacks, handshake_cb, (RawAddress*)&(p_dev->link_spec.addrt.bda), p_dev->link_spec.addrt.type, p_dev->link_spec.transport, (bthh_status_t)hs_data.status); - if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) { - bta_hh_co_get_rpt_rsp(p_dev->dev_handle, (tBTA_HH_STATUS)hs_data.status, NULL, 0); - } + bta_hh_co_get_rpt_rsp(p_dev->dev_handle, (tBTA_HH_STATUS)hs_data.status, NULL, 0); } } @@ -910,9 +908,10 @@ static void hh_vc_unplug_handler(tBTA_HH_CBDATA& dev_status) { BTHH_STATE_UPDATE(p_dev->link_spec, p_dev->dev_status); if (!p_dev->local_vup) { - log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum:: - HIDH_COUNT_VIRTUAL_UNPLUG_REQUESTED_BY_REMOTE_DEVICE, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum:: + HIDH_COUNT_VIRTUAL_UNPLUG_REQUESTED_BY_REMOTE_DEVICE, + 1); } // Remove the HID device @@ -1193,9 +1192,10 @@ bt_status_t btif_hh_connect(const tAclLinkSpec& link_spec) { if (!p_dev && btif_hh_cb.device_num >= BTIF_HH_MAX_HID) { // No space for more HID device now. log::warn("Error, exceeded the maximum supported HID device number {}", BTIF_HH_MAX_HID); - log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum:: - HIDH_COUNT_CONNECT_REQ_WHEN_MAX_DEVICE_LIMIT_REACHED, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum:: + HIDH_COUNT_CONNECT_REQ_WHEN_MAX_DEVICE_LIMIT_REACHED, + 1); return BT_STATUS_NOMEM; } @@ -2030,7 +2030,7 @@ static bt_status_t get_report(RawAddress* bd_addr, tBLE_ADDR_TYPE addr_type, return BT_STATUS_DEVICE_NOT_FOUND; } else if (((int)reportType) <= BTA_HH_RPTT_RESRV || ((int)reportType) > BTA_HH_RPTT_FEATURE) { log::error("report type={} not supported", reportType); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_COUNT_WRONG_REPORT_TYPE, 1); return BT_STATUS_UNSUPPORTED; } else { @@ -2102,7 +2102,7 @@ static bt_status_t set_report(RawAddress* bd_addr, tBLE_ADDR_TYPE addr_type, return BT_STATUS_DEVICE_NOT_FOUND; } else if (((int)reportType) <= BTA_HH_RPTT_RESRV || ((int)reportType) > BTA_HH_RPTT_FEATURE) { log::error("report type={} not supported", reportType); - log_counter_metrics_btif( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_COUNT_WRONG_REPORT_TYPE, 1); return BT_STATUS_UNSUPPORTED; } else { diff --git a/system/btif/src/btif_metrics_logging.cc b/system/btif/src/btif_metrics_logging.cc deleted file mode 100644 index 40f2fed315..0000000000 --- a/system/btif/src/btif_metrics_logging.cc +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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. - */ - -#include "btif/include/btif_metrics_logging.h" - -#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h> -#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h> - -#include "main/shim/metrics_api.h" -#include "types/raw_address.h" - -void log_a2dp_audio_underrun_event(const RawAddress& address, uint64_t encoding_interval_millis, - int num_missing_pcm_bytes) { - bluetooth::shim::LogMetricA2dpAudioUnderrunEvent(address, encoding_interval_millis, - num_missing_pcm_bytes); -} - -void log_a2dp_audio_overrun_event(const RawAddress& address, uint64_t encoding_interval_millis, - int num_dropped_buffers, int num_dropped_encoded_frames, - int num_dropped_encoded_bytes) { - bluetooth::shim::LogMetricA2dpAudioOverrunEvent(address, encoding_interval_millis, - num_dropped_buffers, num_dropped_encoded_frames, - num_dropped_encoded_bytes); -} - -void log_a2dp_playback_event(const RawAddress& address, int playback_state, int audio_coding_mode) { - bluetooth::shim::LogMetricA2dpPlaybackEvent(address, playback_state, audio_coding_mode); -} - -void log_a2dp_session_metrics_event(const RawAddress& address, int64_t audio_duration_ms, - int media_timer_min_ms, int media_timer_max_ms, - int media_timer_avg_ms, int total_scheduling_count, - int buffer_overruns_max_count, int buffer_overruns_total, - float buffer_underruns_average, int buffer_underruns_count, - int64_t codec_index, bool is_a2dp_offload) { - bluetooth::shim::LogMetricA2dpSessionMetricsEvent( - address, audio_duration_ms, media_timer_min_ms, media_timer_max_ms, media_timer_avg_ms, - total_scheduling_count, buffer_overruns_max_count, buffer_overruns_total, - buffer_underruns_average, buffer_underruns_count, codec_index, is_a2dp_offload); -} - -void log_read_rssi_result(const RawAddress& address, uint16_t handle, uint32_t cmd_status, - int8_t rssi) { - bluetooth::shim::LogMetricReadRssiResult(address, handle, cmd_status, rssi); -} - -void log_read_failed_contact_counter_result(const RawAddress& address, uint16_t handle, - uint32_t cmd_status, int32_t failed_contact_counter) { - bluetooth::shim::LogMetricReadFailedContactCounterResult(address, handle, cmd_status, - failed_contact_counter); -} - -void log_read_tx_power_level_result(const RawAddress& address, uint16_t handle, uint32_t cmd_status, - int32_t transmit_power_level) { - bluetooth::shim::LogMetricReadTxPowerLevelResult(address, handle, cmd_status, - transmit_power_level); -} - -void log_socket_connection_state(const RawAddress& address, int port, int type, - android::bluetooth::SocketConnectionstateEnum connection_state, - int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port, - android::bluetooth::SocketRoleEnum socket_role, - uint64_t connection_duration_ms, - android::bluetooth::SocketErrorEnum error_code, - bool is_hardware_offload) { - bluetooth::shim::LogMetricSocketConnectionState( - address, port, type, connection_state, tx_bytes, rx_bytes, uid, server_port, socket_role, - connection_duration_ms, error_code, is_hardware_offload); -} - -void log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum key, int64_t value) { - bluetooth::shim::CountCounterMetrics(key, value); -} - -bool init_metric_id_allocator(const std::unordered_map<RawAddress, int>& paired_device_map, - bluetooth::shim::CallbackLegacy save_device_callback, - bluetooth::shim::CallbackLegacy forget_device_callback) { - return bluetooth::shim::InitMetricIdAllocator(paired_device_map, std::move(save_device_callback), - std::move(forget_device_callback)); -} - -bool close_metric_id_allocator() { return bluetooth::shim::CloseMetricIdAllocator(); } - -int allocate_metric_id_from_metric_id_allocator(const RawAddress& address) { - return bluetooth::shim::AllocateIdFromMetricIdAllocator(address); -} - -int save_metric_id_from_metric_id_allocator(const RawAddress& address) { - return bluetooth::shim::SaveDeviceOnMetricIdAllocator(address); -} - -void forget_device_from_metric_id_allocator(const RawAddress& address) { - bluetooth::shim::ForgetDeviceFromMetricIdAllocator(address); -} - -bool is_valid_id_from_metric_id_allocator(const int id) { - return bluetooth::shim::IsValidIdFromMetricIdAllocator(id); -} diff --git a/system/btif/src/btif_sock_logging.cc b/system/btif/src/btif_sock_logging.cc index 111e52002b..8847daa7f1 100644 --- a/system/btif/src/btif_sock_logging.cc +++ b/system/btif/src/btif_sock_logging.cc @@ -23,9 +23,9 @@ #include <atomic> -#include "btif/include/btif_metrics_logging.h" #include "btif/include/btif_sock.h" #include "common/time_util.h" +#include "main/shim/metrics_api.h" #include "types/raw_address.h" #define SOCK_LOGGER_SIZE_MAX 16 @@ -79,7 +79,7 @@ void btif_sock_connection_logger(const RawAddress& address, int port, int type, } clock_gettime(CLOCK_REALTIME, &connection_logger[index].timestamp); - log_socket_connection_state( + bluetooth::shim::LogMetricSocketConnectionState( address, port, type, toConnectionStateEnum(state), tx_bytes, rx_bytes, uid, server_port, toSocketRoleEnum(role), getConnectionDuration(connection_start_time_ms), toSocketErrorEnum(error_code), data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD); diff --git a/system/btif/src/btif_sock_rfc.cc b/system/btif/src/btif_sock_rfc.cc index 4c75b0f355..1ea4bf9981 100644 --- a/system/btif/src/btif_sock_rfc.cc +++ b/system/btif/src/btif_sock_rfc.cc @@ -33,7 +33,6 @@ #include "bta/include/bta_jv_co.h" #include "bta/include/bta_rfcomm_metrics.h" #include "bta/include/bta_rfcomm_scn.h" -#include "btif/include/btif_metrics_logging.h" #include "btif/include/btif_sock.h" #include "btif/include/btif_sock_l2cap.h" #include "btif/include/btif_sock_logging.h" @@ -45,6 +44,7 @@ #include "include/hardware/bt_sock.h" #include "lpp/lpp_offload_interface.h" #include "main/shim/entry.h" +#include "main/shim/metrics_api.h" #include "osi/include/allocator.h" #include "osi/include/compat.h" #include "osi/include/list.h" @@ -909,12 +909,12 @@ static void on_rfc_close(tBTA_JV_RFCOMM_CLOSE* /* p_close */, uint32_t id) { log::warn("RFCOMM slot with id {} not found.", id); return; } - log_socket_connection_state(slot->addr, slot->id, BTSOCK_RFCOMM, - android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTING, 0, 0, - slot->app_uid, slot->scn, - slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN - : android::bluetooth::SOCKET_ROLE_CONNECTION, - 0, android::bluetooth::SOCKET_ERROR_NONE, slot->data_path); + bluetooth::shim::LogMetricSocketConnectionState( + slot->addr, slot->id, BTSOCK_RFCOMM, + android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTING, 0, 0, slot->app_uid, slot->scn, + slot->f.server ? android::bluetooth::SOCKET_ROLE_LISTEN + : android::bluetooth::SOCKET_ROLE_CONNECTION, + 0, android::bluetooth::SOCKET_ERROR_NONE, slot->data_path); cleanup_rfc_slot(slot, BTSOCK_ERROR_NONE); } diff --git a/system/btif/test/btif_core_test.cc b/system/btif/test/btif_core_test.cc index 7342a17b99..3073bd194c 100644 --- a/system/btif/test/btif_core_test.cc +++ b/system/btif/test/btif_core_test.cc @@ -207,7 +207,8 @@ class BtifCoreTest : public ::testing::Test { protected: void SetUp() override { callback_map_.clear(); - bluetooth::hci::testing::mock_controller_ = &controller_; + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); bluetooth::testing::set_hal_cbacks(&callbacks); auto promise = std::promise<void>(); auto future = promise.get_future(); @@ -223,17 +224,17 @@ protected: callback_map_["callback_thread_event"] = [&promise]() { promise.set_value(); }; CleanCoreInterface(); ASSERT_EQ(std::future_status::ready, future.wait_for(timeout_time)); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); callback_map_.erase("callback_thread_event"); } - bluetooth::hci::testing::MockControllerInterface controller_; }; class BtifCoreWithControllerTest : public BtifCoreTest { protected: void SetUp() override { BtifCoreTest::SetUp(); - ON_CALL(controller_, SupportsSniffSubrating).WillByDefault(Return(true)); + ON_CALL(*bluetooth::hci::testing::mock_controller_, SupportsSniffSubrating) + .WillByDefault(Return(true)); } void TearDown() override { BtifCoreTest::TearDown(); } @@ -761,12 +762,13 @@ class BtifCoreWithVendorSupportTest : public BtifCoreWithControllerTest { protected: void SetUp() override { BtifCoreWithControllerTest::SetUp(); - bluetooth::hci::testing::mock_hci_layer_ = &hci_; + bluetooth::hci::testing::mock_hci_layer_ = + std::make_unique<bluetooth::hci::testing::MockHciLayer>(); test::mock::osi_properties::osi_property_get.body = get_properties; std::promise<void> configuration_promise; auto configuration_done = configuration_promise.get_future(); - EXPECT_CALL(hci_, + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, EnqueueCommand(_, Matcher<ContextualOnceCallback<void(CommandCompleteView)>>(_))) .WillOnce( // Replace with real PDL for 0xfc17 @@ -784,7 +786,7 @@ protected: configuration_promise.set_value(); }) .RetiresOnSaturation(); - EXPECT_CALL(hci_, + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, EnqueueCommand(_, Matcher<ContextualOnceCallback<void(CommandCompleteView)>>(_))) .WillOnce([](std::unique_ptr<CommandBuilder> cmd, ContextualOnceCallback<void(CommandCompleteView)> callback) { @@ -798,7 +800,8 @@ protected: callback(response); }) .RetiresOnSaturation(); - EXPECT_CALL(hci_, RegisterVendorSpecificEventHandler(VseSubeventCode::BQR_EVENT, _)) + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, + RegisterVendorSpecificEventHandler(VseSubeventCode::BQR_EVENT, _)) .WillOnce(SaveArg<1>(&this->vse_callback_)); do_in_main_thread(BindOnce([]() { bluetooth::bqr::EnableBtQualityReport(get_main()); })); ASSERT_EQ(std::future_status::ready, configuration_done.wait_for(std::chrono::seconds(1))); @@ -808,18 +811,18 @@ protected: std::promise<void> disable_promise; auto disable_future = disable_promise.get_future(); auto set_promise = [&disable_promise]() { disable_promise.set_value(); }; - EXPECT_CALL(hci_, UnregisterVendorSpecificEventHandler(VseSubeventCode::BQR_EVENT)); - EXPECT_CALL(hci_, + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, + UnregisterVendorSpecificEventHandler(VseSubeventCode::BQR_EVENT)); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, EnqueueCommand(_, Matcher<ContextualOnceCallback<void(CommandCompleteView)>>(_))) .WillOnce(Invoke(set_promise)) .RetiresOnSaturation(); do_in_main_thread(BindOnce([]() { bluetooth::bqr::DisableBtQualityReport(); })); ASSERT_EQ(std::future_status::ready, disable_future.wait_for(std::chrono::seconds(1))); - bluetooth::hci::testing::mock_hci_layer_ = nullptr; + bluetooth::hci::testing::mock_hci_layer_.reset(); BtifCoreWithControllerTest::TearDown(); } - bluetooth::hci::testing::MockHciLayer hci_; ContextualCallback<void(VendorSpecificEventView)> vse_callback_; }; diff --git a/system/common/Android.bp b/system/common/Android.bp index c192613dbc..a22a733e75 100644 --- a/system/common/Android.bp +++ b/system/common/Android.bp @@ -32,17 +32,6 @@ cc_library_static { canonical_path_from_root: false, export_proto_headers: true, }, - target: { - android: { - srcs: [ - "metrics.cc", - ], - static_libs: ["libstatslog_bt"], - }, - host: { - srcs: ["metrics_linux.cc"], - }, - }, shared_libs: [ "libcrypto", "libcutils", diff --git a/system/common/BUILD.gn b/system/common/BUILD.gn index a1884973dd..5b0852bd36 100644 --- a/system/common/BUILD.gn +++ b/system/common/BUILD.gn @@ -19,8 +19,6 @@ static_library("common") { "address_obfuscator.cc", "le_conn_params.cc", "message_loop_thread.cc", - "metric_id_allocator.cc", - "metrics_linux.cc", "os_utils.cc", "repeating_timer.cc", "stop_watch_legacy.cc", @@ -30,7 +28,6 @@ static_library("common") { include_dirs = [ "//bt/system/", "//bt/system/stack/include", - "//bt/system/linux_include", ] deps = [ diff --git a/system/common/metrics.cc b/system/common/metrics.cc deleted file mode 100644 index a3b3eea450..0000000000 --- a/system/common/metrics.cc +++ /dev/null @@ -1,433 +0,0 @@ -/****************************************************************************** - * - * Copyright 2016 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "common/metrics.h" - -#include <base/base64.h> -#include <bluetooth/log.h> -#include <frameworks/proto_logging/stats/enums/bluetooth/le/enums.pb.h> -#include <include/hardware/bt_av.h> -#include <statslog_bt.h> -#include <unistd.h> - -#include <algorithm> -#include <cerrno> -#include <cstdint> -#include <cstring> -#include <memory> -#include <mutex> // NOLINT -#include <utility> - -#include "common/address_obfuscator.h" -#include "common/leaky_bonded_queue.h" -#include "common/time_util.h" -#include "hci/address.h" -#include "main/shim/metric_id_api.h" -#include "osi/include/osi.h" -#include "types/raw_address.h" - -namespace std { -template <> -struct formatter<android::bluetooth::DirectionEnum> - : enum_formatter<android::bluetooth::DirectionEnum> {}; -template <> -struct formatter<android::bluetooth::SocketConnectionstateEnum> - : enum_formatter<android::bluetooth::SocketConnectionstateEnum> {}; -template <> -struct formatter<android::bluetooth::SocketRoleEnum> - : enum_formatter<android::bluetooth::SocketRoleEnum> {}; -template <> -struct formatter<android::bluetooth::AddressTypeEnum> - : enum_formatter<android::bluetooth::AddressTypeEnum> {}; -template <> -struct formatter<android::bluetooth::DeviceInfoSrcEnum> - : enum_formatter<android::bluetooth::DeviceInfoSrcEnum> {}; -template <> -struct formatter<android::bluetooth::SocketErrorEnum> - : enum_formatter<android::bluetooth::SocketErrorEnum> {}; -} // namespace std - -namespace bluetooth { -namespace common { - -using bluetooth::hci::Address; - -void LogLinkLayerConnectionEvent(const RawAddress* address, uint32_t connection_handle, - android::bluetooth::DirectionEnum direction, uint16_t link_type, - uint32_t hci_cmd, uint16_t hci_event, uint16_t hci_ble_event, - uint16_t cmd_status, uint16_t reason_code) { - std::string obfuscated_id; - int metric_id = 0; - if (address != nullptr) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(*address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(*address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField bytes_field(address != nullptr ? obfuscated_id.c_str() : nullptr, - address != nullptr ? obfuscated_id.size() : 0); - int ret = stats_write(BLUETOOTH_LINK_LAYER_CONNECTION_EVENT, bytes_field, connection_handle, - direction, link_type, hci_cmd, hci_event, hci_ble_event, cmd_status, - reason_code, metric_id); - if (ret < 0) { - log::warn( - "failed to log status 0x{:x}, reason 0x{:x} from cmd 0x{:x}, event " - "0x{:x}, ble_event 0x{:x} for {}, handle {}, type 0x{:x}, error {}", - cmd_status, reason_code, hci_cmd, hci_event, hci_ble_event, *address, connection_handle, - link_type, ret); - } -} - -void LogHciTimeoutEvent(uint32_t hci_cmd) { - int ret = stats_write(BLUETOOTH_HCI_TIMEOUT_REPORTED, static_cast<int64_t>(hci_cmd)); - if (ret < 0) { - log::warn("failed for opcode 0x{:x}, error {}", hci_cmd, ret); - } -} - -void LogRemoteVersionInfo(uint16_t handle, uint8_t status, uint8_t version, - uint16_t manufacturer_name, uint16_t subversion) { - int ret = stats_write(BLUETOOTH_REMOTE_VERSION_INFO_REPORTED, handle, status, version, - manufacturer_name, subversion); - if (ret < 0) { - log::warn( - "failed for handle {}, status 0x{:x}, version 0x{:x}, " - "manufacturer_name 0x{:x}, subversion 0x{:x}, error {}", - handle, status, version, manufacturer_name, subversion, ret); - } -} - -void LogA2dpAudioUnderrunEvent(const RawAddress& address, uint64_t encoding_interval_millis, - int num_missing_pcm_bytes) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField bytes_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int64_t encoding_interval_nanos = encoding_interval_millis * 1000000; - int ret = stats_write(BLUETOOTH_A2DP_AUDIO_UNDERRUN_REPORTED, bytes_field, - encoding_interval_nanos, num_missing_pcm_bytes, metric_id); - if (ret < 0) { - log::warn( - "failed for {}, encoding_interval_nanos {}, num_missing_pcm_bytes {}, " - "error {}", - address, encoding_interval_nanos, num_missing_pcm_bytes, ret); - } -} - -void LogA2dpAudioOverrunEvent(const RawAddress& address, uint64_t encoding_interval_millis, - int num_dropped_buffers, int num_dropped_encoded_frames, - int num_dropped_encoded_bytes) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField bytes_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int64_t encoding_interval_nanos = encoding_interval_millis * 1000000; - int ret = stats_write(BLUETOOTH_A2DP_AUDIO_OVERRUN_REPORTED, bytes_field, encoding_interval_nanos, - num_dropped_buffers, num_dropped_encoded_frames, num_dropped_encoded_bytes, - metric_id); - if (ret < 0) { - log::warn( - "failed to log for {}, encoding_interval_nanos {}, num_dropped_buffers " - "{}, num_dropped_encoded_frames {}, num_dropped_encoded_bytes {}, " - "error {}", - address, encoding_interval_nanos, num_dropped_buffers, num_dropped_encoded_frames, - num_dropped_encoded_bytes, ret); - } -} - -void LogA2dpPlaybackEvent(const RawAddress& address, int playback_state, int audio_coding_mode) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField bytes_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int ret = stats_write(BLUETOOTH_A2DP_PLAYBACK_STATE_CHANGED, bytes_field, playback_state, - audio_coding_mode, metric_id); - if (ret < 0) { - log::warn( - "failed to log for {}, playback_state {}, audio_coding_mode {}, error " - "{}", - address, playback_state, audio_coding_mode, ret); - } -} - -void LogReadRssiResult(const RawAddress& address, uint16_t handle, uint32_t cmd_status, - int8_t rssi) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField bytes_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int ret = stats_write(BLUETOOTH_DEVICE_RSSI_REPORTED, bytes_field, handle, cmd_status, rssi, - metric_id); - if (ret < 0) { - log::warn("failed for {}, handle {}, status 0x{:x}, rssi {} dBm, error {}", address, handle, - cmd_status, rssi, ret); - } -} - -void LogReadFailedContactCounterResult(const RawAddress& address, uint16_t handle, - uint32_t cmd_status, int32_t failed_contact_counter) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField bytes_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int ret = stats_write(BLUETOOTH_DEVICE_FAILED_CONTACT_COUNTER_REPORTED, bytes_field, handle, - cmd_status, failed_contact_counter, metric_id); - if (ret < 0) { - log::warn( - "failed for {}, handle {}, status 0x{:x}, failed_contact_counter {} " - "packets, error {}", - address, handle, cmd_status, failed_contact_counter, ret); - } -} - -void LogReadTxPowerLevelResult(const RawAddress& address, uint16_t handle, uint32_t cmd_status, - int32_t transmit_power_level) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField bytes_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int ret = stats_write(BLUETOOTH_DEVICE_TX_POWER_LEVEL_REPORTED, bytes_field, handle, cmd_status, - transmit_power_level, metric_id); - if (ret < 0) { - log::warn( - "failed for {}, handle {}, status 0x{:x}, transmit_power_level {} " - "packets, error {}", - address, handle, cmd_status, transmit_power_level, ret); - } -} - -void LogSmpPairingEvent(const RawAddress& address, uint8_t smp_cmd, - android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField obfuscated_id_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int ret = stats_write(BLUETOOTH_SMP_PAIRING_EVENT_REPORTED, obfuscated_id_field, smp_cmd, - direction, smp_fail_reason, metric_id); - if (ret < 0) { - log::warn( - "failed for {}, smp_cmd 0x{:x}, direction {}, smp_fail_reason 0x{:x}, " - "error {}", - address, smp_cmd, direction, smp_fail_reason, ret); - } -} - -void LogClassicPairingEvent(const RawAddress& address, uint16_t handle, uint32_t hci_cmd, - uint16_t hci_event, uint16_t cmd_status, uint16_t reason_code, - int64_t event_value) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField obfuscated_id_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int ret = stats_write(BLUETOOTH_CLASSIC_PAIRING_EVENT_REPORTED, obfuscated_id_field, handle, - hci_cmd, hci_event, cmd_status, reason_code, event_value, metric_id); - if (ret < 0) { - log::warn( - "failed for {}, handle {}, hci_cmd 0x{:x}, hci_event 0x{:x}, " - "cmd_status 0x{:x}, reason 0x{:x}, event_value {}, error {}", - address, handle, hci_cmd, hci_event, cmd_status, reason_code, event_value, ret); - } -} - -void LogSdpAttribute(const RawAddress& address, uint16_t protocol_uuid, uint16_t attribute_id, - size_t attribute_size, const char* attribute_value) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField obfuscated_id_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - BytesField attribute_field(attribute_value, attribute_size); - int ret = stats_write(BLUETOOTH_SDP_ATTRIBUTE_REPORTED, obfuscated_id_field, protocol_uuid, - attribute_id, attribute_field, metric_id); - if (ret < 0) { - log::warn("failed for {}, protocol_uuid 0x{:x}, attribute_id 0x{:x}, error {}", address, - protocol_uuid, attribute_id, ret); - } -} - -void LogSocketConnectionState(const RawAddress& address, int port, int type, - android::bluetooth::SocketConnectionstateEnum connection_state, - int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port, - android::bluetooth::SocketRoleEnum socket_role, - uint64_t connection_duration_ms, - android::bluetooth::SocketErrorEnum error_code, - bool is_hardware_offload) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField obfuscated_id_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int ret = stats_write(BLUETOOTH_SOCKET_CONNECTION_STATE_CHANGED, obfuscated_id_field, port, type, - connection_state, tx_bytes, rx_bytes, uid, server_port, socket_role, - metric_id, static_cast<int64_t>(connection_duration_ms), error_code, - is_hardware_offload); - if (ret < 0) { - log::warn( - "failed for {}, port {}, type {}, state {}, tx_bytes {}, rx_bytes {}, " - "uid {}, server_port {}, socket_role {}, error {}, connection_duration_ms {}, " - "socket_error_code {}, " - "is_hardware_offload {}", - address, port, type, connection_state, tx_bytes, rx_bytes, uid, server_port, - socket_role, ret, connection_duration_ms, error_code, is_hardware_offload); - } -} - -void LogManufacturerInfo(const RawAddress& address, - android::bluetooth::AddressTypeEnum address_type, - android::bluetooth::DeviceInfoSrcEnum source_type, - const std::string& source_name, const std::string& manufacturer, - const std::string& model, const std::string& hardware_version, - const std::string& software_version) { - std::string obfuscated_id; - int metric_id = 0; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - metric_id = bluetooth::shim::AllocateIdFromMetricIdAllocator(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField obfuscated_id_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int ret = stats_write(BLUETOOTH_DEVICE_INFO_REPORTED, obfuscated_id_field, source_type, - source_name.c_str(), manufacturer.c_str(), model.c_str(), - hardware_version.c_str(), software_version.c_str(), metric_id, address_type, - address.address[5], address.address[4], address.address[3]); - if (ret < 0) { - log::warn( - "failed for {}, source_type {}, source_name {}, manufacturer {}, model " - "{}, hardware_version {}, software_version {} MAC address type {} MAC " - "address prefix {} {} {}, error {}", - address, source_type, source_name, manufacturer, model, hardware_version, - software_version, address_type, address.address[5], address.address[4], - address.address[3], ret); - } -} - -void LogBluetoothHalCrashReason(const RawAddress& address, uint32_t error_code, - uint32_t vendor_error_code) { - std::string obfuscated_id; - if (!address.IsEmpty()) { - obfuscated_id = AddressObfuscator::GetInstance()->Obfuscate(address); - } - // nullptr and size 0 represent missing value for obfuscated_id - BytesField obfuscated_id_field(address.IsEmpty() ? nullptr : obfuscated_id.c_str(), - address.IsEmpty() ? 0 : obfuscated_id.size()); - int ret = stats_write(BLUETOOTH_HAL_CRASH_REASON_REPORTED, 0, obfuscated_id_field, error_code, - vendor_error_code); - if (ret < 0) { - log::warn("failed for {}, error_code 0x{:x}, vendor_error_code 0x{:x}, error {}", address, - error_code, vendor_error_code, ret); - } -} - -void LogLeAudioConnectionSessionReported( - int32_t group_size, int32_t group_metric_id, int64_t connection_duration_nanos, - const std::vector<int64_t>& device_connecting_offset_nanos, - const std::vector<int64_t>& device_connected_offset_nanos, - const std::vector<int64_t>& device_connection_duration_nanos, - const std::vector<int32_t>& device_connection_status, - const std::vector<int32_t>& device_disconnection_status, - const std::vector<RawAddress>& device_address, - const std::vector<int64_t>& streaming_offset_nanos, - const std::vector<int64_t>& streaming_duration_nanos, - const std::vector<int32_t>& streaming_context_type) { - std::vector<int32_t> device_metric_id(device_address.size()); - for (uint64_t i = 0; i < device_address.size(); i++) { - if (!device_address[i].IsEmpty()) { - device_metric_id[i] = bluetooth::shim::AllocateIdFromMetricIdAllocator(device_address[i]); - } else { - device_metric_id[i] = 0; - } - } - int ret = stats_write(LE_AUDIO_CONNECTION_SESSION_REPORTED, group_size, group_metric_id, - connection_duration_nanos, device_connecting_offset_nanos, - device_connected_offset_nanos, device_connection_duration_nanos, - device_connection_status, device_disconnection_status, device_metric_id, - streaming_offset_nanos, streaming_duration_nanos, streaming_context_type); - if (ret < 0) { - log::warn( - "failed for group {}device_connecting_offset_nanos[{}], " - "device_connected_offset_nanos[{}], " - "device_connection_duration_nanos[{}], device_connection_status[{}], " - "device_disconnection_status[{}], device_metric_id[{}], " - "streaming_offset_nanos[{}], streaming_duration_nanos[{}], " - "streaming_context_type[{}]", - group_metric_id, device_connecting_offset_nanos.size(), - device_connected_offset_nanos.size(), device_connection_duration_nanos.size(), - device_connection_status.size(), device_disconnection_status.size(), - device_metric_id.size(), streaming_offset_nanos.size(), streaming_duration_nanos.size(), - streaming_context_type.size()); - } -} - -void LogLeAudioBroadcastSessionReported(int64_t duration_nanos) { - int ret = stats_write(LE_AUDIO_BROADCAST_SESSION_REPORTED, duration_nanos); - if (ret < 0) { - log::warn("failed for duration={}", duration_nanos); - } -} - -} // namespace common - -} // namespace bluetooth diff --git a/system/common/metrics.h b/system/common/metrics.h deleted file mode 100644 index 4ccb47f64c..0000000000 --- a/system/common/metrics.h +++ /dev/null @@ -1,272 +0,0 @@ -/****************************************************************************** - * - * Copyright 2016 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#pragma once - -#include <bta/include/bta_api.h> -#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h> -#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h> -#include <frameworks/proto_logging/stats/enums/bluetooth/le/enums.pb.h> -#include <stdint.h> - -#include <memory> -#include <string> -#include <vector> - -#include "hci/address.h" -#include "os/metrics.h" -#include "types/raw_address.h" - -namespace bluetooth { - -namespace common { - -/** - * Unknown connection handle for metrics purpose - */ -static const uint32_t kUnknownConnectionHandle = 0xFFFF; - -/** - * Log link layer connection event - * - * @param address Stack wide consistent Bluetooth address of this event, - * nullptr if unknown - * @param connection_handle connection handle of this event, - * {@link kUnknownConnectionHandle} if unknown - * @param direction direction of this connection - * @param link_type type of the link - * @param hci_cmd HCI command opecode associated with this event, if any - * @param hci_event HCI event code associated with this event, if any - * @param hci_ble_event HCI BLE event code associated with this event, if any - * @param cmd_status Command status associated with this event, if any - * @param reason_code Reason code associated with this event, if any - */ -void LogLinkLayerConnectionEvent(const RawAddress* address, uint32_t connection_handle, - android::bluetooth::DirectionEnum direction, uint16_t link_type, - uint32_t hci_cmd, uint16_t hci_event, uint16_t hci_ble_event, - uint16_t cmd_status, uint16_t reason_code); - -/** - * Logs when Bluetooth controller failed to reply with command status within - * a timeout period after receiving an HCI command from the host - * - * @param hci_cmd opcode of HCI command that caused this timeout - */ -void LogHciTimeoutEvent(uint32_t hci_cmd); - -/** - * Logs when we receive Bluetooth Read Remote Version Information Complete - * Event from the remote device, as documented by the Bluetooth Core HCI - * specification - * - * Reference: 5.0 Core Specification, Vol 2, Part E, Page 1118 - * - * @param handle handle of associated ACL connection - * @param status HCI command status of this event - * @param version version code from read remote version complete event - * @param manufacturer_name manufacturer code from read remote version complete - * event - * @param subversion subversion code from read remote version complete event - */ -void LogRemoteVersionInfo(uint16_t handle, uint8_t status, uint8_t version, - uint16_t manufacturer_name, uint16_t subversion); - -/** - * Log A2DP audio buffer underrun event - * - * @param address A2DP device associated with this event - * @param encoding_interval_millis encoding interval in milliseconds - * @param num_missing_pcm_bytes number of PCM bytes that cannot be read from - * the source - */ -void LogA2dpAudioUnderrunEvent(const RawAddress& address, uint64_t encoding_interval_millis, - int num_missing_pcm_bytes); - -/** - * Log A2DP audio buffer overrun event - * - * @param address A2DP device associated with this event - * @param encoding_interval_millis encoding interval in milliseconds - * @param num_dropped_buffers number of encoded buffers dropped from Tx queue - * @param num_dropped_encoded_frames number of encoded frames dropped from Tx - * queue - * @param num_dropped_encoded_bytes number of encoded bytes dropped from Tx - * queue - */ -void LogA2dpAudioOverrunEvent(const RawAddress& address, uint64_t encoding_interval_millis, - int num_dropped_buffers, int num_dropped_encoded_frames, - int num_dropped_encoded_bytes); - -/** - * Log A2DP playback state changed event - * - * @param address A2DP device associated with this event - * @param playback_state audio playback state - * @param audio_coding_mode audio codec encoding mode - */ -void LogA2dpPlaybackEvent(const RawAddress& address, int playback_state, int audio_coding_mode); - -/** - * Log read RSSI result - * - * @param address device associated with this event - * @param handle connection handle of this event, - * {@link kUnknownConnectionHandle} if unknown - * @param cmd_status command status from read RSSI command - * @param rssi rssi value in dBm - */ -void LogReadRssiResult(const RawAddress& address, uint16_t handle, uint32_t cmd_status, - int8_t rssi); - -/** - * Log failed contact counter report - * - * @param address device associated with this event - * @param handle connection handle of this event, - * {@link kUnknownConnectionHandle} if unknown - * @param cmd_status command status from read failed contact counter command - * @param failed_contact_counter Number of consecutive failed contacts for a - * connection corresponding to the Handle - */ -void LogReadFailedContactCounterResult(const RawAddress& address, uint16_t handle, - uint32_t cmd_status, int32_t failed_contact_counter); - -/** - * Log transmit power level for a particular device after read - * - * @param address device associated with this event - * @param handle connection handle of this event, - * {@link kUnknownConnectionHandle} if unknown - * @param cmd_status command status from read failed contact counter command - * @param transmit_power_level transmit power level for connection to this - * device - */ -void LogReadTxPowerLevelResult(const RawAddress& address, uint16_t handle, uint32_t cmd_status, - int32_t transmit_power_level); - -/** - * Logs when there is an event related to Bluetooth Security Manager Protocol - * - * @param address address of associated device - * @param smp_cmd SMP command code associated with this event - * @param direction direction of this SMP command - * @param smp_fail_reason SMP pairing failure reason code from SMP spec - */ -void LogSmpPairingEvent(const RawAddress& address, uint8_t smp_cmd, - android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason); - -/** - * Logs there is an event related Bluetooth classic pairing - * - * @param address address of associated device - * @param handle connection handle of this event, - * {@link kUnknownConnectionHandle} if unknown - * @param hci_cmd HCI command associated with this event - * @param hci_event HCI event associated with this event - * @param cmd_status Command status associated with this event - * @param reason_code Reason code associated with this event - * @param event_value A status value related to this specific event - */ -void LogClassicPairingEvent(const RawAddress& address, uint16_t handle, uint32_t hci_cmd, - uint16_t hci_event, uint16_t cmd_status, uint16_t reason_code, - int64_t event_value); - -/** - * Logs when certain Bluetooth SDP attributes are discovered - * - * @param address address of associated device - * @param protocol_uuid 16 bit protocol UUID from Bluetooth Assigned Numbers - * @param attribute_id 16 bit attribute ID from Bluetooth Assigned Numbers - * @param attribute_size size of this attribute - * @param attribute_value pointer to the attribute data, must be larger than - * attribute_size - */ -void LogSdpAttribute(const RawAddress& address, uint16_t protocol_uuid, uint16_t attribute_id, - size_t attribute_size, const char* attribute_value); - -/** - * Logs when there is a change in Bluetooth socket connection state - * - * @param address address of associated device, empty if this is a server port - * @param port port of this socket connection - * @param type type of socket - * @param connection_state socket connection state - * @param tx_bytes number of bytes transmitted - * @param rx_bytes number of bytes received - * @param server_port server port of this socket, if any. When both - * |server_port| and |port| fields are populated, |port| must be spawned - * by |server_port| - * @param socket_role role of this socket, server or connection - * @param uid socket owner's uid - * @param connection_duration_ms duration of socket connection in milliseconds - * @param error_code error code of socket failures - * @param is_hardware_offload whether this is a offload socket - */ -void LogSocketConnectionState(const RawAddress& address, int port, int type, - android::bluetooth::SocketConnectionstateEnum connection_state, - int64_t tx_bytes, int64_t rx_bytes, int uid, int server_port, - android::bluetooth::SocketRoleEnum socket_role, - uint64_t connection_duration_ms, - android::bluetooth::SocketErrorEnum error_code, - bool is_hardware_offload); - -/** - * Logs when a Bluetooth device's manufacturer information is learnt - * - * @param address address of associated device - * @param source_type where is this device info obtained from - * @param source_name name of the data source, internal or external - * @param manufacturer name of the manufacturer of this device - * @param model model of this device - * @param hardware_version hardware version of this device - * @param software_version software version of this device - */ -void LogManufacturerInfo(const RawAddress& address, - android::bluetooth::AddressTypeEnum address_type, - android::bluetooth::DeviceInfoSrcEnum source_type, - const std::string& source_name, const std::string& manufacturer, - const std::string& model, const std::string& hardware_version, - const std::string& software_version); - -/** - * Logs when received Bluetooth HAL crash reason report. - * - * @param address current connected address. - * @param error_code the crash reason from bluetooth hal - * @param vendor_error_code the vendor crash reason from bluetooth Firmware - */ -void LogBluetoothHalCrashReason(const RawAddress& address, uint32_t error_code, - uint32_t vendor_error_code); - -void LogLeAudioConnectionSessionReported( - int32_t group_size, int32_t group_metric_id, int64_t connection_duration_nanos, - const std::vector<int64_t>& device_connecting_offset_nanos, - const std::vector<int64_t>& device_connected_offset_nanos, - const std::vector<int64_t>& device_connection_duration_nanos, - const std::vector<int32_t>& device_connection_status, - const std::vector<int32_t>& device_disconnection_status, - const std::vector<RawAddress>& device_address, - const std::vector<int64_t>& streaming_offset_nanos, - const std::vector<int64_t>& streaming_duration_nanos, - const std::vector<int32_t>& streaming_context_type); - -void LogLeAudioBroadcastSessionReported(int64_t duration_nanos); - -} // namespace common - -} // namespace bluetooth diff --git a/system/common/metrics_linux.cc b/system/common/metrics_linux.cc deleted file mode 100644 index 3283619415..0000000000 --- a/system/common/metrics_linux.cc +++ /dev/null @@ -1,111 +0,0 @@ -/****************************************************************************** - * - * Copyright 2018 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include <bluetooth/log.h> - -#include "common/metrics.h" -#include "types/raw_address.h" - -namespace bluetooth { - -namespace common { - -void LogClassicPairingEvent(const RawAddress& /* address */, uint16_t /* handle */, - uint32_t /* hci_cmd */, uint16_t /* hci_event */, - uint16_t /* cmd_status */, uint16_t /* reason_code */, - int64_t /* event_value */) {} - -void LogSocketConnectionState(const RawAddress& /* address */, int /* port */, int /* type */, - android::bluetooth::SocketConnectionstateEnum /* connection_state */, - int64_t /* tx_bytes */, int64_t /* rx_bytes */, int /* uid */, - int /* server_port */, - android::bluetooth::SocketRoleEnum /* socket_role */, - uint64_t /* connection_duration_ms */, - android::bluetooth::SocketErrorEnum /* error_code */, - bool /* is_hardware_offload */) {} - -void LogHciTimeoutEvent(uint32_t /* hci_cmd */) {} - -void LogA2dpAudioUnderrunEvent(const RawAddress& /* address */, - uint64_t /* encoding_interval_millis */, - int /* num_missing_pcm_bytes */) {} - -void LogA2dpAudioOverrunEvent(const RawAddress& /* address */, - uint64_t /* encoding_interval_millis */, - int /* num_dropped_buffers */, int /* num_dropped_encoded_frames */, - int /* num_dropped_encoded_bytes */) {} - -void LogA2dpPlaybackEvent(const RawAddress& /* address */, int /* playback_state */, - int /* audio_coding_mode */) {} - -void LogBluetoothHalCrashReason(const RawAddress& /* address */, uint32_t /* error_code */, - uint32_t /* vendor_error_code */) {} - -void LogReadRssiResult(const RawAddress& /* address */, uint16_t /* handle */, - uint32_t /* cmd_status */, int8_t /* rssi */) {} - -void LogReadFailedContactCounterResult(const RawAddress& /* address */, uint16_t /* handle */, - uint32_t /* cmd_status */, - int32_t /* failed_contact_counter */) {} - -void LogReadTxPowerLevelResult(const RawAddress& /* address */, uint16_t /* handle */, - uint32_t /* cmd_status */, int32_t /* transmit_power_level */) {} - -void LogRemoteVersionInfo(uint16_t /* handle */, uint8_t /* status */, uint8_t /* version */, - uint16_t /* manufacturer_name */, uint16_t /* subversion */) {} - -void LogLinkLayerConnectionEvent(const RawAddress* /* address */, uint32_t /* connection_handle */, - android::bluetooth::DirectionEnum /* direction */, - uint16_t /* link_type */, uint32_t /* hci_cmd */, - uint16_t /* hci_event */, uint16_t /* hci_ble_event */, - uint16_t /* cmd_status */, uint16_t /* reason_code */) {} - -void LogManufacturerInfo(const RawAddress& /* address */, - android::bluetooth::AddressTypeEnum /* address_type */, - android::bluetooth::DeviceInfoSrcEnum /* source_type */, - const std::string& /* source_name */, - const std::string& /* manufacturer */, const std::string& /* model */, - const std::string& /* hardware_version */, - const std::string& /* software_version */) {} - -void LogSdpAttribute(const RawAddress& /* address */, uint16_t /* protocol_uuid */, - uint16_t /* attribute_id */, size_t /* attribute_size */, - const char* /* attribute_value */) {} - -void LogSmpPairingEvent(const RawAddress& /* address */, uint8_t /* smp_cmd */, - android::bluetooth::DirectionEnum /* direction */, - uint8_t /* smp_fail_reason */) {} - -void LogLeAudioConnectionSessionReported( - int32_t /* group_size */, int32_t /* group_metric_id */, - int64_t /* connection_duration_nanos */, - const std::vector<int64_t>& /* device_connecting_offset_nanos */, - const std::vector<int64_t>& /* device_connected_offset_nanos */, - const std::vector<int64_t>& /* device_connection_duration_nanos */, - const std::vector<int32_t>& /* device_connection_status */, - const std::vector<int32_t>& /* device_disconnection_status */, - const std::vector<RawAddress>& /* device_address */, - const std::vector<int64_t>& /* streaming_offset_nanos */, - const std::vector<int64_t>& /* streaming_duration_nanos */, - const std::vector<int32_t>& /* streaming_context_type */) {} - -void LogLeAudioBroadcastSessionReported(int64_t /* duration_nanos */) {} - -} // namespace common - -} // namespace bluetooth diff --git a/system/conf/interop_database.conf b/system/conf/interop_database.conf index ecf3da0b07..d921db421d 100644 --- a/system/conf/interop_database.conf +++ b/system/conf/interop_database.conf @@ -895,3 +895,8 @@ BSK10 = Name_Based [INTEROP_DISABLE_HF_PROFILE] JBL Flip 5 = Name_Based JBL Flip 6 = Name_Based + +# Some devices don't respond to LE appearance read request. +[INTEROP_DISABLE_READ_LE_APPEARANCE] +L1_L = Name_Based +L1_R = Name_Based diff --git a/system/device/include/interop.h b/system/device/include/interop.h index 22233bcd65..d72315d1b0 100644 --- a/system/device/include/interop.h +++ b/system/device/include/interop.h @@ -358,16 +358,20 @@ typedef enum { // Peer can request proper latency based on its power state later. INTEROP_HID_PREF_CONN_ZERO_LATENCY, - // Some HOGP devices have the report map longer than the maximum GATT attribute value length (512 - // bytes). + // Some HOGP devices have the report map longer than the maximum GATT + // attribute value length (512 bytes). INTEROP_HOGP_LONG_REPORT, - // Some HOGP devices requires MTU exchange be part of the initial setup to function. + // Some HOGP devices requires MTU exchange be part of the initial setup to + // function. INTEROP_HOGP_FORCE_MTU_EXCHANGE, // Some devices claim to support HFP in EIR but does not actually support it. INTEROP_DISABLE_HF_PROFILE, + // Some devices don't respond to LE appearance read request. + INTEROP_DISABLE_READ_LE_APPEARANCE, + END_OF_INTEROP_LIST } interop_feature_t; diff --git a/system/device/src/interop.cc b/system/device/src/interop.cc index 60d90cf6d6..44313664ed 100644 --- a/system/device/src/interop.cc +++ b/system/device/src/interop.cc @@ -392,6 +392,7 @@ static const char* interop_feature_string_(const interop_feature_t feature) { CASE_RETURN_STR(INTEROP_HOGP_LONG_REPORT); CASE_RETURN_STR(INTEROP_HOGP_FORCE_MTU_EXCHANGE); CASE_RETURN_STR(INTEROP_DISABLE_HF_PROFILE); + CASE_RETURN_STR(INTEROP_DISABLE_READ_LE_APPEARANCE); } return UNKNOWN_INTEROP_FEATURE; } diff --git a/system/gd/Android.bp b/system/gd/Android.bp index 26f31f0b8e..45555f130a 100644 --- a/system/gd/Android.bp +++ b/system/gd/Android.bp @@ -194,7 +194,7 @@ cc_library_static { "packages/modules/Bluetooth/system", ], apex_available: ["com.android.bt"], - min_sdk_version: "31", + min_sdk_version: "33", static_libs: [ "bluetooth_flags_c_lib", "libchrome", @@ -357,8 +357,8 @@ cc_test { srcs: [ ":BluetoothPacketTestSources", ":TestCommonMockFunctions", + ":TestMockMainShim", ":TestMockMainShimEntry", - ":TestMockStackMetrics", "common/bidi_queue_unittest.cc", "common/blocking_queue_unittest.cc", "common/byte_array_test.cc", @@ -414,6 +414,9 @@ cc_test { "storage/mutation_test.cc", "storage/storage_module_test.cc", ], + cflags: [ + "-DUSE_FAKE_TIMERS", + ], static_libs: [ "bluetooth_flags_c_lib_for_test", "libbase", @@ -581,11 +584,12 @@ cc_fuzz { defaults: ["gd_fuzz_defaults"], srcs: [ ":TestCommonMockFunctions", - ":TestMockStackMetrics", + ":TestMockMainShim", "hci/fuzz/acl_manager_fuzz_test.cc", ], include_dirs: [ "packages/modules/Bluetooth/system", + "packages/modules/Bluetooth/system/include", ], static_libs: [ "libbt-platform-protos-lite", diff --git a/system/gd/common/audit_log.cc b/system/gd/common/audit_log.cc index e83c2894f8..2e112a0c34 100644 --- a/system/gd/common/audit_log.cc +++ b/system/gd/common/audit_log.cc @@ -16,6 +16,8 @@ #include "common/audit_log.h" +#include <format> + #ifdef __ANDROID__ #include <log/log_event_list.h> #endif // __ANDROID__ @@ -43,8 +45,8 @@ void LogConnectionAdminAuditEvent([[maybe_unused]] const char* action, android_log_event_list(SEC_TAG_BLUETOOTH_CONNECTION) << address.ToRedactedStringForLogging() - << /* success */ int32_t(status == hci::ErrorCode::SUCCESS) << action << ": " - << ErrorCodeText(status) << LOG_ID_SECURITY; + << /* success */ int32_t(status == hci::ErrorCode::SUCCESS) + << std::format("{}: {}", action, ErrorCodeText(status)) << LOG_ID_SECURITY; #endif /* defined(__ANDROID__) && !defined (FUZZ_TARGET) */ } diff --git a/system/gd/hal/hci_hal.h b/system/gd/hal/hci_hal.h index 49f007ba55..2c028c3b6f 100644 --- a/system/gd/hal/hci_hal.h +++ b/system/gd/hal/hci_hal.h @@ -51,6 +51,10 @@ public: // Send an ISO data packet from the controller to the host // @param data the ISO HCI packet to be passed to the host stack virtual void isoDataReceived(HciPacket data) = 0; + + // This function is invoked when the controller encounters an error requiring + // the Bluetooth stack to initiate a reset. + virtual void controllerNeedsReset() {} }; // Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHci.hal in Android @@ -101,9 +105,6 @@ public: // Get the MSFT opcode (as specified in Microsoft-defined Bluetooth HCI // extensions) virtual uint16_t getMsftOpcode() { return 0; } - - // Mark the controller as broken to prevent further read / write operation. - virtual void markControllerBroken() { return; } }; // LINT.ThenChange(fuzz/fuzz_hci_hal.h) diff --git a/system/gd/hal/hci_hal_android_test.cc b/system/gd/hal/hci_hal_android_test.cc index 247f15745f..f128f508cf 100644 --- a/system/gd/hal/hci_hal_android_test.cc +++ b/system/gd/hal/hci_hal_android_test.cc @@ -20,6 +20,7 @@ #include <queue> #include <thread> +#include "com_android_bluetooth_flags.h" #include "hal/hci_backend.h" #include "hal/hci_hal.h" #include "os/thread.h" @@ -79,10 +80,13 @@ protected: } void TearDown() override { - fake_registry_.StopAll(); handler_->Clear(); - delete thread_; + if (com::android::bluetooth::flags::same_handler_for_all_modules()) { + handler_->WaitUntilStopped(bluetooth::kHandlerStopTimeout); + } + fake_registry_.StopAll(); delete handler_; + delete thread_; } HciHal* hal; diff --git a/system/gd/hal/hci_hal_host.cc b/system/gd/hal/hci_hal_host.cc index f441fcf212..bf020a2e02 100644 --- a/system/gd/hal/hci_hal_host.cc +++ b/system/gd/hal/hci_hal_host.cc @@ -262,9 +262,6 @@ public: void sendHciCommand(HciPacket command) override { std::lock_guard<std::mutex> lock(api_mutex_); - if (controller_broken_) { - return; - } log::assert_that(sock_fd_ != INVALID_FD, "assert failed: sock_fd_ != INVALID_FD"); std::vector<uint8_t> packet = std::move(command); btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, @@ -275,9 +272,6 @@ public: void sendAclData(HciPacket data) override { std::lock_guard<std::mutex> lock(api_mutex_); - if (controller_broken_) { - return; - } log::assert_that(sock_fd_ != INVALID_FD, "assert failed: sock_fd_ != INVALID_FD"); std::vector<uint8_t> packet = std::move(data); btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, @@ -288,10 +282,6 @@ public: void sendScoData(HciPacket data) override { std::lock_guard<std::mutex> lock(api_mutex_); - if (controller_broken_) { - return; - } - log::assert_that(sock_fd_ != INVALID_FD, "assert failed: sock_fd_ != INVALID_FD"); std::vector<uint8_t> packet = std::move(data); btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, @@ -302,9 +292,6 @@ public: void sendIsoData(HciPacket data) override { std::lock_guard<std::mutex> lock(api_mutex_); - if (controller_broken_) { - return; - } log::assert_that(sock_fd_ != INVALID_FD, "assert failed: sock_fd_ != INVALID_FD"); std::vector<uint8_t> packet = std::move(data); btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, @@ -317,15 +304,6 @@ public: return os::Management::getInstance().getVendorSpecificCode(MGMT_VS_OPCODE_MSFT); } - void markControllerBroken() override { - std::lock_guard<std::mutex> lock(api_mutex_); - if (controller_broken_) { - log::error("Controller already marked as broken!"); - return; - } - controller_broken_ = true; - } - protected: void ListDependencies(ModuleList* list) const { list->add<LinkClocker>(); } @@ -337,8 +315,7 @@ protected: // We don't want to crash when the chipset is broken. if (sock_fd_ == INVALID_FD) { log::error("Failed to connect to HCI socket. Aborting HAL initialization process."); - controller_broken_ = true; - kill(getpid(), SIGTERM); + incoming_packet_callback_->controllerNeedsReset(); return; } @@ -392,7 +369,6 @@ private: std::queue<std::vector<uint8_t>> hci_outgoing_queue_; SnoopLogger* btsnoop_logger_ = nullptr; LinkClocker* link_clocker_ = nullptr; - bool controller_broken_ = false; void write_to_fd(HciPacket packet) { // TODO(chromeos-bt-team@): replace this with new queue when it's ready @@ -414,8 +390,8 @@ private: hci_outgoing_queue_.pop(); if (bytes_written == -1) { log::error("Can't write to socket: {}", strerror(errno)); - markControllerBroken(); - kill(getpid(), SIGTERM); + incoming_packet_callback_->controllerNeedsReset(); + return; } if (hci_outgoing_queue_.empty()) { hci_incoming_thread_.GetReactor()->ModifyRegistration(reactable_, @@ -439,15 +415,13 @@ private: // we don't want crash when the chipset is broken. if (received_size == -1) { log::error("Can't receive from socket: {}", strerror(errno)); - markControllerBroken(); - kill(getpid(), SIGTERM); + incoming_packet_callback_->controllerNeedsReset(); return; } if (received_size == 0) { log::warn("Can't read H4 header. EOF received"); - markControllerBroken(); - kill(getpid(), SIGTERM); + incoming_packet_callback_->controllerNeedsReset(); return; } diff --git a/system/gd/hal/hci_hal_host_test.cc b/system/gd/hal/hci_hal_host_test.cc index 4f4c6bc6d0..d4539d6c3b 100644 --- a/system/gd/hal/hci_hal_host_test.cc +++ b/system/gd/hal/hci_hal_host_test.cc @@ -32,6 +32,7 @@ #include <utility> #include <vector> +#include "com_android_bluetooth_flags.h" #include "hal/hci_hal.h" #include "hal/serialize_packet.h" #include "os/thread.h" @@ -155,12 +156,15 @@ protected: void TearDown() override { hal_->unregisterIncomingPacketCallback(); + handler_->Clear(); + if (com::android::bluetooth::flags::same_handler_for_all_modules()) { + handler_->WaitUntilStopped(bluetooth::kHandlerStopTimeout); + } fake_registry_.StopAll(); + delete handler_; close(fake_server_socket_); - handler_->Clear(); delete fake_server_; delete thread_; - delete handler_; } void SetFakeServerSocketToBlocking() { diff --git a/system/gd/hal/snoop_logger.h b/system/gd/hal/snoop_logger.h index b009add89c..b0783442b3 100644 --- a/system/gd/hal/snoop_logger.h +++ b/system/gd/hal/snoop_logger.h @@ -17,6 +17,7 @@ #pragma once #include <bluetooth/log.h> +#include <com_android_bluetooth_flags.h> #include <fstream> #include <string> @@ -195,6 +196,13 @@ public: }; SnoopLogger(os::Handler* handler); + ~SnoopLogger() { + if (!com::android::bluetooth::flags::same_handler_for_all_modules()) { + GetHandler()->Clear(); + GetHandler()->WaitUntilStopped(std::chrono::milliseconds(2000)); + delete GetHandler(); + } + } // Returns the maximum number of packets per file // Changes to this value is only effective after restarting Bluetooth diff --git a/system/gd/hci/acl_manager.cc b/system/gd/hci/acl_manager.cc index 73f455f168..280cc237b4 100644 --- a/system/gd/hci/acl_manager.cc +++ b/system/gd/hci/acl_manager.cc @@ -260,21 +260,6 @@ void AclManager::CreateLeConnection(AddressWithType address_with_type, bool is_d CallOn(pimpl_->le_impl_, &le_impl::create_le_connection, address_with_type, true, is_direct); } -void AclManager::IsOnBackgroundList(AddressWithType address_with_type, std::promise<bool> promise) { - CallOn(pimpl_->le_impl_, &le_impl::is_on_background_connection_list, address_with_type, - std::move(promise)); -} - -void AclManager::SetLeSuggestedDefaultDataParameters(uint16_t octets, uint16_t time) { - CallOn(pimpl_->le_impl_, &le_impl::set_le_suggested_default_data_parameters, octets, time); -} - -void AclManager::LeSetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, - uint16_t max_latency, uint16_t cont_num, uint16_t sup_tout) { - CallOn(pimpl_->le_impl_, &le_impl::LeSetDefaultSubrate, subrate_min, subrate_max, max_latency, - cont_num, sup_tout); -} - void AclManager::SetPrivacyPolicyForInitiatorAddress( LeAddressManager::AddressPolicy address_policy, AddressWithType fixed_address, std::chrono::milliseconds minimum_rotation_time, diff --git a/system/gd/hci/acl_manager.h b/system/gd/hci/acl_manager.h index b6932eee52..f38f1ff689 100644 --- a/system/gd/hci/acl_manager.h +++ b/system/gd/hci/acl_manager.h @@ -86,12 +86,6 @@ public: // Generates OnLeConnectSuccess if connected, or OnLeConnectFail otherwise virtual void CreateLeConnection(AddressWithType address_with_type, bool is_direct); - // Ask the controller for specific data parameters - virtual void SetLeSuggestedDefaultDataParameters(uint16_t octets, uint16_t time); - - virtual void LeSetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t sup_tout); - virtual void SetPrivacyPolicyForInitiatorAddress(LeAddressManager::AddressPolicy address_policy, AddressWithType fixed_address, std::chrono::milliseconds minimum_rotation_time, @@ -108,7 +102,6 @@ public: // connected virtual void CancelConnect(Address address); virtual void RemoveFromBackgroundList(AddressWithType address_with_type); - virtual void IsOnBackgroundList(AddressWithType address_with_type, std::promise<bool> promise); virtual void CancelLeConnect(AddressWithType address_with_type); diff --git a/system/gd/hci/acl_manager/le_impl.h b/system/gd/hci/acl_manager/le_impl.h index a6761e38b7..122f76525e 100644 --- a/system/gd/hci/acl_manager/le_impl.h +++ b/system/gd/hci/acl_manager/le_impl.h @@ -39,11 +39,11 @@ #include "hci/hci_packets.h" #include "hci/le_address_manager.h" #include "macros.h" +#include "main/shim/metrics_api.h" #include "os/alarm.h" #include "os/handler.h" #include "os/system_properties.h" #include "stack/include/btm_ble_api_types.h" -#include "stack/include/stack_metrics_logging.h" namespace bluetooth { namespace hci { @@ -426,7 +426,7 @@ public: return; } - log_le_connection_status(address, true /* is_connect */, status); + bluetooth::shim::LogMetricLeConnectionStatus(address, true /* is_connect */, status); const bool in_filter_accept_list = is_device_in_accept_list(remote_address); @@ -586,7 +586,8 @@ public: arm_on_resume_ = true; add_device_to_accept_list(remote_address); } - log_le_connection_status(remote_address.GetAddress(), false /* is_connect */, reason); + bluetooth::shim::LogMetricLeConnectionStatus(remote_address.GetAddress(), + false /* is_connect */, reason); } void on_le_connection_update_complete(LeMetaEventView view) { @@ -724,7 +725,8 @@ public: } void add_device_to_accept_list(AddressWithType address_with_type) { - log_le_device_in_accept_list(address_with_type.GetAddress(), true /* is_add */); + bluetooth::shim::LogMetricLeDeviceInAcceptList(address_with_type.GetAddress(), + true /* is_add */); if (connections.alreadyConnected(address_with_type)) { log::info("Device already connected, return"); return; @@ -747,7 +749,8 @@ public: } void remove_device_from_accept_list(AddressWithType address_with_type) { - log_le_device_in_accept_list(address_with_type.GetAddress(), false /* is_add */); + bluetooth::shim::LogMetricLeDeviceInAcceptList(address_with_type.GetAddress(), + false /* is_add */); if (accept_list.find(address_with_type) == accept_list.end()) { log::warn("Device not in acceptlist and cannot be removed: {}", address_with_type); return; @@ -1060,15 +1063,12 @@ public: add_device_to_accept_list(address_with_type); } - if (com::android::bluetooth::flags:: - improve_create_connection_for_already_connecting_device()) { - bool in_accept_list_due_to_direct_connect = - direct_connections_.find(address_with_type) != direct_connections_.end(); + bool in_accept_list_due_to_direct_connect = + direct_connections_.find(address_with_type) != direct_connections_.end(); - if (already_in_accept_list && (in_accept_list_due_to_direct_connect || !is_direct)) { - log::info("Device {} already in accept list. Stop here.", address_with_type); - return; - } + if (already_in_accept_list && (in_accept_list_due_to_direct_connect || !is_direct)) { + log::info("Device {} already in accept list. Stop here.", address_with_type); + return; } if (is_direct) { @@ -1132,8 +1132,9 @@ public: remove_device_from_accept_list(address_with_type); } // Temporary mapping the error code to PAGE_TIMEOUT - log_le_connection_completion(address_with_type.GetAddress(), ErrorCode::PAGE_TIMEOUT, - true /* is locally initiated */); + bluetooth::shim::LogMetricLeConnectionCompletion(address_with_type.GetAddress(), + ErrorCode::PAGE_TIMEOUT, + true /* is locally initiated */); le_client_handler_->Post(common::BindOnce( &LeConnectionCallbacks::OnLeConnectFail, common::Unretained(le_client_callbacks_), address_with_type, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)); @@ -1145,25 +1146,6 @@ public: remove_device_from_accept_list(address_with_type); } - void set_le_suggested_default_data_parameters(uint16_t length, uint16_t time) { - auto packet = LeWriteSuggestedDefaultDataLengthBuilder::Create(length, time); - le_acl_connection_interface_->EnqueueCommand( - std::move(packet), handler_->BindOnce([](CommandCompleteView /* complete */) {})); - } - - void LeSetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t sup_tout) { - le_acl_connection_interface_->EnqueueCommand( - LeSetDefaultSubrateBuilder::Create(subrate_min, subrate_max, max_latency, cont_num, - sup_tout), - handler_->BindOnce([](CommandCompleteView complete) { - auto complete_view = LeSetDefaultSubrateCompleteView::Create(complete); - log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); - ErrorCode status = complete_view.GetStatus(); - log::assert_that(status == ErrorCode::SUCCESS, "Status = {}", ErrorCodeText(status)); - })); - } - void clear_resolving_list() { le_address_manager_->ClearResolvingList(); } void set_privacy_policy_for_initiator_address(LeAddressManager::AddressPolicy address_policy, @@ -1249,12 +1231,6 @@ public: background_connections_.erase(address_with_type); } - void is_on_background_connection_list(AddressWithType address_with_type, - std::promise<bool> promise) { - promise.set_value(background_connections_.find(address_with_type) != - background_connections_.end()); - } - void OnPause() override { // bluetooth::hci::LeAddressManagerCallback if (!address_manager_registered) { log::warn("Unregistered!"); diff --git a/system/gd/hci/acl_manager/le_impl_test.cc b/system/gd/hci/acl_manager/le_impl_test.cc index 66bc16bbd8..f54d316d30 100644 --- a/system/gd/hci/acl_manager/le_impl_test.cc +++ b/system/gd/hci/acl_manager/le_impl_test.cc @@ -284,164 +284,6 @@ protected: hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); } - void test_direct_connection_after_background_connection() { - set_random_device_address_policy(); - - hci::AddressWithType address({0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, - AddressType::PUBLIC_DEVICE_ADDRESS); - - // arrange: Create background connection. Remember that acl_manager adds device background list - le_impl_->add_device_to_background_connection_list(address); - le_impl_->create_le_connection(address, true, /* is_direct */ false); - hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST); - hci_layer_->IncomingEvent( - LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); - auto raw_bg_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); - hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); - sync_handler(); - - // act: Create direct connection - le_impl_->create_le_connection(address, true, /* is_direct */ true); - auto cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL); - if (cancel_connection.IsValid()) { - hci_layer_->IncomingEvent( - LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); - hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( - ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL, - AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000, - ClockAccuracy::PPM_30)); - } - auto raw_direct_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); - - // assert - auto bg_create_connection = - LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( - AclCommandView::Create(raw_bg_create_connection))); - EXPECT_TRUE(bg_create_connection.IsValid()); - auto direct_create_connection = - LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( - AclCommandView::Create(raw_direct_create_connection))); - EXPECT_TRUE(direct_create_connection.IsValid()); - log::info("Scan Interval {}", direct_create_connection.GetLeScanInterval()); - ASSERT_NE(direct_create_connection.GetLeScanInterval(), - bg_create_connection.GetLeScanInterval()); - - hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); - sync_handler(); - - // Check state is ARMED - ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_); - - // Simulate timeout on direct connect. Verify background connect is still in place - EXPECT_CALL(mock_le_connection_callbacks_, - OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)) - .Times(1); - le_impl_->on_create_connection_timeout(address); - sync_handler(); - cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL); - hci_layer_->IncomingEvent( - LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); - hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( - ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL, - AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000, - ClockAccuracy::PPM_30)); - EXPECT_TRUE(cancel_connection.IsValid()); - raw_bg_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); - bg_create_connection = LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( - AclCommandView::Create(raw_bg_create_connection))); - EXPECT_TRUE(bg_create_connection.IsValid()); - sync_handler(); - ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty()); - - hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); - sync_handler(); - - // Check state is ARMED - ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_); - } - - void test_direct_connect_after_direct_connect() { - set_random_device_address_policy(); - - hci::AddressWithType address({0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, - AddressType::PUBLIC_DEVICE_ADDRESS); - - // Create first direct connection - le_impl_->create_le_connection(address, true, /* is_direct */ true); - hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST); - hci_layer_->IncomingEvent( - LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); - auto raw_direct_1_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); - hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); - sync_handler(); - - // Check state is ARMED - ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_); - - // assert - auto direct_1_create_connection = - LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( - AclCommandView::Create(raw_direct_1_create_connection))); - EXPECT_TRUE(direct_1_create_connection.IsValid()); - - log::info("Second direct connect to the same device"); - - // Create second direct connection - le_impl_->create_le_connection(address, true, /* is_direct */ true); - sync_handler(); - - CommandView cancel_connection = CommandView::Create( - PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>())); - - if (!com::android::bluetooth::flags:: - improve_create_connection_for_already_connecting_device()) { - cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL); - if (cancel_connection.IsValid()) { - hci_layer_->IncomingEvent( - LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); - hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( - ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL, - AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000, - ClockAccuracy::PPM_30)); - } - - auto raw_direct_2_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); - - auto direct_2_create_connection = - LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( - AclCommandView::Create(raw_direct_2_create_connection))); - EXPECT_TRUE(direct_2_create_connection.IsValid()); - hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); - sync_handler(); - } else { - hci_layer_->AssertNoQueuedCommand(); - } - - log::info("Simulate timeout"); - - EXPECT_CALL(mock_le_connection_callbacks_, - OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)) - .Times(1); - le_impl_->on_create_connection_timeout(address); - sync_handler(); - cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL); - EXPECT_TRUE(cancel_connection.IsValid()); - hci_layer_->IncomingEvent( - LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); - hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( - ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL, - AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000, - ClockAccuracy::PPM_30)); - sync_handler(); - ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty()); - - hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST); - hci_layer_->IncomingEvent( - LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); - hci_layer_->AssertNoQueuedCommand(); - ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_); - } - // Need to store the LeAclConnection so it is not immediately dropped => disconnected std::unique_ptr<LeAclConnection> create_enhanced_connection(std::string remote_address_string, int handle) { @@ -1475,29 +1317,6 @@ TEST_F(LeImplTest, cancel_connect) { ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty()); } -TEST_F(LeImplTest, set_le_suggested_default_data_parameters) { - le_impl_->set_le_suggested_default_data_parameters(kLength, kTime); - sync_handler(); - auto view = CreateLeConnectionManagementCommandView<LeWriteSuggestedDefaultDataLengthView>( - hci_layer_->GetCommand()); - ASSERT_TRUE(view.IsValid()); - ASSERT_EQ(kLength, view.GetTxOctets()); - ASSERT_EQ(kTime, view.GetTxTime()); -} - -TEST_F(LeImplTest, LeSetDefaultSubrate) { - le_impl_->LeSetDefaultSubrate(kIntervalMin, kIntervalMax, kLatency, kContinuationNumber, - kTimeout); - sync_handler(); - auto view = CreateAclCommandView<LeSetDefaultSubrateView>(hci_layer_->GetCommand()); - ASSERT_TRUE(view.IsValid()); - ASSERT_EQ(kIntervalMin, view.GetSubrateMin()); - ASSERT_EQ(kIntervalMax, view.GetSubrateMax()); - ASSERT_EQ(kLatency, view.GetMaxLatency()); - ASSERT_EQ(kContinuationNumber, view.GetContinuationNumber()); - ASSERT_EQ(kTimeout, view.GetSupervisionTimeout()); -} - enum class ConnectionCompleteType { CONNECTION_COMPLETE, ENHANCED_CONNECTION_COMPLETE }; class LeImplTestParameterizedByConnectionCompleteEventType @@ -1716,29 +1535,138 @@ TEST_F(LeImplTest, DisconnectionAcceptlistCallback) { } TEST_F(LeImplTest, direct_connection_after_background_connection) { - // TODO b/356593752 - remove when test removing flag - com::android::bluetooth::flags::provider_ - ->improve_create_connection_for_already_connecting_device(false); - test_direct_connection_after_background_connection(); -} + set_random_device_address_policy(); + + hci::AddressWithType address({0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, + AddressType::PUBLIC_DEVICE_ADDRESS); + + // arrange: Create background connection. Remember that acl_manager adds device background list + le_impl_->add_device_to_background_connection_list(address); + le_impl_->create_le_connection(address, true, /* is_direct */ false); + hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST); + hci_layer_->IncomingEvent( + LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + auto raw_bg_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); + hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); + sync_handler(); + + // act: Create direct connection + le_impl_->create_le_connection(address, true, /* is_direct */ true); + auto cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL); + if (cancel_connection.IsValid()) { + hci_layer_->IncomingEvent( + LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( + ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL, + AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000, + ClockAccuracy::PPM_30)); + } + auto raw_direct_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); + + // assert + auto bg_create_connection = + LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( + AclCommandView::Create(raw_bg_create_connection))); + EXPECT_TRUE(bg_create_connection.IsValid()); + auto direct_create_connection = + LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( + AclCommandView::Create(raw_direct_create_connection))); + EXPECT_TRUE(direct_create_connection.IsValid()); + log::info("Scan Interval {}", direct_create_connection.GetLeScanInterval()); + ASSERT_NE(direct_create_connection.GetLeScanInterval(), bg_create_connection.GetLeScanInterval()); -TEST_F(LeImplTest, direct_connection_after_background_connection_with_improvement) { - com::android::bluetooth::flags::provider_ - ->improve_create_connection_for_already_connecting_device(true); - test_direct_connection_after_background_connection(); + hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); + sync_handler(); + + // Check state is ARMED + ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_); + + // Simulate timeout on direct connect. Verify background connect is still in place + EXPECT_CALL(mock_le_connection_callbacks_, + OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)) + .Times(1); + le_impl_->on_create_connection_timeout(address); + sync_handler(); + cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL); + hci_layer_->IncomingEvent( + LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( + ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL, + AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000, + ClockAccuracy::PPM_30)); + EXPECT_TRUE(cancel_connection.IsValid()); + raw_bg_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); + bg_create_connection = LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( + AclCommandView::Create(raw_bg_create_connection))); + EXPECT_TRUE(bg_create_connection.IsValid()); + sync_handler(); + ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty()); + + hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); + sync_handler(); + + // Check state is ARMED + ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_); } TEST_F(LeImplTest, direct_connection_after_direct_connection) { - // TODO b/356593752 - remove when test removing flag - com::android::bluetooth::flags::provider_ - ->improve_create_connection_for_already_connecting_device(false); - test_direct_connect_after_direct_connect(); -} + set_random_device_address_policy(); -TEST_F(LeImplTest, direct_connection_after_direct_connection_with_improvement) { - com::android::bluetooth::flags::provider_ - ->improve_create_connection_for_already_connecting_device(true); - test_direct_connect_after_direct_connect(); + hci::AddressWithType address({0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, + AddressType::PUBLIC_DEVICE_ADDRESS); + + // Create first direct connection + le_impl_->create_le_connection(address, true, /* is_direct */ true); + hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST); + hci_layer_->IncomingEvent( + LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + auto raw_direct_1_create_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION); + hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01)); + sync_handler(); + + // Check state is ARMED + ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_); + + // assert + auto direct_1_create_connection = + LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create( + AclCommandView::Create(raw_direct_1_create_connection))); + EXPECT_TRUE(direct_1_create_connection.IsValid()); + + log::info("Second direct connect to the same device"); + + // Create second direct connection + le_impl_->create_le_connection(address, true, /* is_direct */ true); + sync_handler(); + + CommandView cancel_connection = CommandView::Create( + PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>())); + + hci_layer_->AssertNoQueuedCommand(); + + log::info("Simulate timeout"); + + EXPECT_CALL(mock_le_connection_callbacks_, + OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)) + .Times(1); + le_impl_->on_create_connection_timeout(address); + sync_handler(); + cancel_connection = hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION_CANCEL); + EXPECT_TRUE(cancel_connection.IsValid()); + hci_layer_->IncomingEvent( + LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create( + ErrorCode::UNKNOWN_CONNECTION, kHciHandle, Role::CENTRAL, + AddressType::PUBLIC_DEVICE_ADDRESS, Address::kEmpty, 0x0000, 0x0000, 0x0000, + ClockAccuracy::PPM_30)); + sync_handler(); + ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty()); + + hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST); + hci_layer_->IncomingEvent( + LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS)); + hci_layer_->AssertNoQueuedCommand(); + ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_); } TEST_F(LeImplTest, direct_connection_cancel_but_connected) { diff --git a/system/gd/hci/acl_manager/round_robin_scheduler.cc b/system/gd/hci/acl_manager/round_robin_scheduler.cc index ad0e6dc621..89897a82e5 100644 --- a/system/gd/hci/acl_manager/round_robin_scheduler.cc +++ b/system/gd/hci/acl_manager/round_robin_scheduler.cc @@ -17,7 +17,6 @@ #include "hci/acl_manager/round_robin_scheduler.h" #include <bluetooth/log.h> -#include <com_android_bluetooth_flags.h> #include <memory> #include <utility> @@ -65,10 +64,8 @@ void RoundRobinScheduler::Unregister(uint16_t handle) { log::assert_that(acl_queue_handlers_.count(handle) == 1, "assert failed: acl_queue_handlers_.count(handle) == 1"); - if (com::android::bluetooth::flags::drop_acl_fragment_on_disconnect()) { - // Drop the pending fragments and recalculate number_of_sent_packets_ - drop_packet_fragments(handle); - } + // Drop the pending fragments and recalculate number_of_sent_packets_ + drop_packet_fragments(handle); auto& acl_queue_handler = acl_queue_handlers_.find(handle)->second; log::info("unregistering acl_queue handle={}, sent_packets={}", handle, @@ -94,8 +91,7 @@ void RoundRobinScheduler::Unregister(uint16_t handle) { starting_point_ = acl_queue_handlers_.begin(); // Restart sending packets if we got acl credits - if (com::android::bluetooth::flags::drop_acl_fragment_on_disconnect() && - credits_reclaimed_from_zero) { + if (credits_reclaimed_from_zero) { start_round_robin(); } } diff --git a/system/gd/hci/acl_manager/round_robin_scheduler_test.cc b/system/gd/hci/acl_manager/round_robin_scheduler_test.cc index 25bd2aff80..b990332c9e 100644 --- a/system/gd/hci/acl_manager/round_robin_scheduler_test.cc +++ b/system/gd/hci/acl_manager/round_robin_scheduler_test.cc @@ -16,7 +16,6 @@ #include "hci/acl_manager/round_robin_scheduler.h" -#include <com_android_bluetooth_flags.h> #include <gtest/gtest.h> #include "common/bidi_queue.h" @@ -422,8 +421,6 @@ TEST_F(RoundRobinSchedulerTest, receive_le_credit_when_next_fragment_is_classic) } TEST_F(RoundRobinSchedulerTest, unregister_reclaim_credits) { - com::android::bluetooth::flags::provider_->drop_acl_fragment_on_disconnect(true); - uint16_t handle = 0x01; auto connection_queue = std::make_shared<AclConnection::Queue>(20); auto new_connection_queue = std::make_shared<AclConnection::Queue>(20); diff --git a/system/gd/hci/controller.cc b/system/gd/hci/controller.cc index b14e434781..919643f14d 100644 --- a/system/gd/hci/controller.cc +++ b/system/gd/hci/controller.cc @@ -61,9 +61,7 @@ struct Controller::impl { handler->BindOn(this, &Controller::impl::NumberOfCompletedPackets)); set_event_mask(kDefaultEventMask); - if (com::android::bluetooth::flags::encryption_change_v2()) { - set_event_mask_page_2(kDefaultEventMaskPage2); - } + set_event_mask_page_2(kDefaultEventMaskPage2); write_le_host_support(Enable::ENABLED, Enable::DISABLED); hci_->EnqueueCommand( diff --git a/system/gd/hci/distance_measurement_manager.cc b/system/gd/hci/distance_measurement_manager.cc index 6bdfde00b9..6e57f2c9d5 100644 --- a/system/gd/hci/distance_measurement_manager.cc +++ b/system/gd/hci/distance_measurement_manager.cc @@ -441,6 +441,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { it->second.measurement_ongoing = true; it->second.waiting_for_start_callback = true; it->second.local_hci_role = local_hci_role; + it->second.retry_counter_for_create_config = 0; + it->second.retry_counter_for_cs_enable = 0; return true; } @@ -845,6 +847,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { static void reset_tracker_on_stopped(CsTracker& cs_tracker) { cs_tracker.measurement_ongoing = false; cs_tracker.state = CsTrackerState::STOPPED; + cs_tracker.procedure_data_list.clear(); } void handle_cs_setup_failure(uint16_t connection_handle, DistanceMeasurementErrorCode errorCode) { @@ -906,7 +909,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { if (cs_requester_trackers_.find(connection_handle) != cs_requester_trackers_.end()) { reset_tracker_on_stopped(cs_requester_trackers_[connection_handle]); } - } else if (status_view.GetStatus() != ErrorCode::SUCCESS) { + } else if (enable == Enable::ENABLED && status_view.GetStatus() != ErrorCode::SUCCESS) { if (cs_requester_trackers_.count(connection_handle) == 0) { log::error("Error code {} for connection_handle {}. No request tracker found.", ErrorCodeText(status), connection_handle); @@ -919,6 +922,14 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { if (cs_requester_trackers_[connection_handle].retry_counter_for_cs_enable++ >= kMaxRetryCounterForCsEnable) { handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); + } else { + cs_requester_trackers_[connection_handle].procedure_schedule_guard_alarm->Cancel(); + log::info("schedule next procedure enable after {} ms", + cs_requester_trackers_[connection_handle].interval_ms); + cs_requester_trackers_[connection_handle].procedure_schedule_guard_alarm->Schedule( + common::Bind(&impl::send_le_cs_procedure_enable, common::Unretained(this), + connection_handle, Enable::ENABLED), + std::chrono::milliseconds(cs_requester_trackers_[connection_handle].interval_ms)); } } } @@ -1237,25 +1248,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { void on_cs_procedure_enable_complete(LeCsProcedureEnableCompleteView event_view) { log::assert_that(event_view.IsValid(), "assert failed: event_view.IsValid()"); uint16_t connection_handle = event_view.GetConnectionHandle(); - log::debug("on cs procedure enabled complete"); - if (event_view.GetStatus() != ErrorCode::SUCCESS) { - std::string error_code = ErrorCodeText(event_view.GetStatus()); - if (cs_requester_trackers_.count(connection_handle) == 0) { - log::warn( - "Received LeCsProcedureEnableCompleteView with error code {}, No request tracker " - "found", - error_code); - handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); - return; - } - log::warn("Received LeCsProcedureEnableCompleteView with error code {}. Retry counter {}", - error_code, cs_requester_trackers_[connection_handle].retry_counter_for_cs_enable); - if (cs_requester_trackers_[connection_handle].retry_counter_for_cs_enable++ >= - kMaxRetryCounterForCsEnable) { - handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); - } - return; - } + log::debug("Procedure enabled, {}", event_view.ToString()); + uint8_t config_id = event_view.GetConfigId(); CsTracker* live_tracker = nullptr; @@ -1272,7 +1266,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { live_tracker = get_live_tracker(connection_handle, config_id, valid_requester_states, valid_responder_states); if (live_tracker == nullptr) { - log::error("no tracker is available for {}", connection_handle); + log::error("enable - no tracker is available for {}", connection_handle); return; } if (live_tracker->used_config_id != config_id) { @@ -1280,7 +1274,22 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { live_tracker->used_config_id); return; } - log::debug("Procedure enabled, {}", event_view.ToString()); + + if (live_tracker->local_start && event_view.GetStatus() != ErrorCode::SUCCESS) { + log::warn("Received LeCsProcedureEnableCompleteView with error code {}. Retry counter {}", + ErrorCodeText(event_view.GetStatus()), live_tracker->retry_counter_for_cs_enable); + if (live_tracker->retry_counter_for_cs_enable++ >= kMaxRetryCounterForCsEnable) { + handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); + } else { + live_tracker->procedure_schedule_guard_alarm->Cancel(); + log::info("schedule next procedure enable after {} ms", live_tracker->interval_ms); + live_tracker->procedure_schedule_guard_alarm->Schedule( + common::Bind(&impl::send_le_cs_procedure_enable, common::Unretained(this), + connection_handle, Enable::ENABLED), + std::chrono::milliseconds(live_tracker->interval_ms)); + } + return; + } live_tracker->state = CsTrackerState::STARTED; live_tracker->selected_tx_power = event_view.GetSelectedTxPower(); live_tracker->n_procedure_count = event_view.GetProcedureCount(); @@ -1297,38 +1306,45 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { if (live_tracker->n_procedure_count >= 1) { live_tracker->procedure_schedule_guard_alarm->Cancel(); log::info("schedule next procedure enable after {} ms", schedule_interval); - cs_requester_trackers_[connection_handle].procedure_schedule_guard_alarm->Schedule( + live_tracker->procedure_schedule_guard_alarm->Schedule( common::Bind(&impl::send_le_cs_procedure_enable, common::Unretained(this), connection_handle, Enable::ENABLED), std::chrono::milliseconds(schedule_interval)); } - } - if (live_tracker->local_start && live_tracker->waiting_for_start_callback) { - live_tracker->waiting_for_start_callback = false; - distance_measurement_callbacks_->OnDistanceMeasurementStarted(live_tracker->address, - METHOD_CS); - } - if (live_tracker->local_start && is_hal_v2()) { - // reset the procedure sequence - live_tracker->procedure_sequence_after_enable = -1; - ranging_hal_->UpdateProcedureEnableConfig(connection_handle, event_view); + if (live_tracker->waiting_for_start_callback) { + live_tracker->waiting_for_start_callback = false; + distance_measurement_callbacks_->OnDistanceMeasurementStarted(live_tracker->address, + METHOD_CS); + } + if (is_hal_v2()) { + // reset the procedure sequence + live_tracker->procedure_sequence_after_enable = -1; + ranging_hal_->UpdateProcedureEnableConfig(connection_handle, event_view); + } } } else if (event_view.GetState() == Enable::DISABLED) { - uint8_t valid_requester_states = static_cast<uint8_t>(CsTrackerState::STARTED); - uint8_t valid_responder_states = static_cast<uint8_t>(CsTrackerState::STARTED); - live_tracker = get_live_tracker(connection_handle, config_id, valid_requester_states, - valid_responder_states); - if (live_tracker == nullptr) { - log::error("no tracker is available for {}", connection_handle); - return; + if (event_view.GetStatus() == ErrorCode::SUCCESS) { + // local or remote host requested it. + uint8_t valid_requester_states = static_cast<uint8_t>(CsTrackerState::STARTED); + uint8_t valid_responder_states = static_cast<uint8_t>(CsTrackerState::STARTED); + live_tracker = get_live_tracker(connection_handle, config_id, valid_requester_states, + valid_responder_states); + if (live_tracker == nullptr) { + log::error("disable - no tracker is available for {}", connection_handle); + return; + } + reset_tracker_on_stopped(*live_tracker); + } else { + // work around, controller may send 'DISABLE' complete with error for 'ENABLE' command + auto req_it = cs_requester_trackers_.find(connection_handle); + if (req_it != cs_requester_trackers_.end() && + req_it->second.state == CsTrackerState::WAIT_FOR_PROCEDURE_ENABLED && + config_id == req_it->second.used_config_id) { + log::warn("expect ENABLE complete, bug got DISABLE complete."); + handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); + } } - reset_tracker_on_stopped(*live_tracker); - } - // reset the procedure data list. - std::vector<CsProcedureData>& data_list = live_tracker->procedure_data_list; - while (!data_list.empty()) { - data_list.erase(data_list.begin()); } } diff --git a/system/gd/hci/distance_measurement_manager_test.cc b/system/gd/hci/distance_measurement_manager_test.cc index 98ab5a4573..35a629c53a 100644 --- a/system/gd/hci/distance_measurement_manager_test.cc +++ b/system/gd/hci/distance_measurement_manager_test.cc @@ -21,6 +21,8 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> +#include "common/bind.h" +#include "common/strings.h" #include "hal/ranging_hal.h" #include "hal/ranging_hal_mock.h" #include "hci/acl_manager_mock.h" @@ -31,14 +33,20 @@ #include "hci/hci_layer.h" #include "hci/hci_layer_fake.h" #include "module.h" +#include "os/fake_timer/fake_timerfd.h" #include "packet/packet_view.h" #include "ras/ras_packets.h" +using bluetooth::os::fake_timer::fake_timerfd_advance; +using bluetooth::os::fake_timer::fake_timerfd_reset; +using testing::_; using testing::AtLeast; using testing::Return; namespace { -constexpr auto kTimeout = std::chrono::seconds(1); +static constexpr auto kTimeout = std::chrono::seconds(1); +static constexpr uint8_t kMaxRetryCounterForCreateConfig = 0x03; +static constexpr uint8_t kMaxRetryCounterForCsEnable = 0x03; } namespace bluetooth { @@ -52,6 +60,9 @@ protected: }; class TestAclManager : public testing::MockAclManager { +public: + void AddDeviceToRelaxedConnectionIntervalList(const Address /*address*/) override {} + protected: void Start() override {} void Stop() override {} @@ -65,7 +76,7 @@ struct CsReadCapabilitiesCompleteEvent { uint8_t num_antennas_supported = 2; uint8_t max_antenna_paths_supported = 4; CsRoleSupported roles_supported = {/*initiator=*/1, /*reflector=*/1}; - CsOptionalModesSupported modes_supported = {/*mode_3=*/1}; + unsigned char modes_supported = {/*mode_3=*/1}; CsRttCapability rtt_capability = {/*rtt_aa_only_n=*/1, /*rtt_sounding_n=*/1, /*rtt_random_payload_n=*/1}; uint8_t rtt_aa_only_n = 1; @@ -74,7 +85,7 @@ struct CsReadCapabilitiesCompleteEvent { CsOptionalNadmSoundingCapability nadm_sounding_capability = { /*normalized_attack_detector_metric=*/1}; CsOptionalNadmRandomCapability nadm_random_capability = {/*normalized_attack_detector_metric=*/1}; - CsOptionalCsSyncPhysSupported cs_sync_phys_supported = {/*le_2m_phy=*/1}; + CsOptionalCsSyncPhysSupported cs_sync_phys_supported = {/*le_2m_phy=*/1, /*le_2m_2bt_phy=*/0}; CsOptionalSubfeaturesSupported subfeatures_supported = {/*no_frequency_actuation_error=*/1, /*channel_selection_algorithm=*/1, /*phase_based_ranging=*/1}; @@ -101,6 +112,53 @@ struct CsReadCapabilitiesCompleteEvent { uint8_t tx_snr_capability = 1; }; +struct CsConfigCompleteEvent { + ErrorCode status = ErrorCode::SUCCESS; + uint8_t config_id = 0; + CsAction action = CsAction::CONFIG_CREATED; + CsMainModeType main_mode_type = CsMainModeType::MODE_2; + CsSubModeType sub_mode_type = CsSubModeType::UNUSED; + uint8_t min_main_mode_steps = 3; // 0x02 to 0xFF + uint8_t max_main_mode_steps = 100; // 0x02 to 0xFF + uint8_t main_mode_repetition = 0; // 0x00 to 0x03 + uint8_t mode_0_steps = 1; // 0x01 to 0x03 + CsRole cs_role = CsRole::INITIATOR; + CsRttType rtt_type = CsRttType::RTT_AA_ONLY; + CsSyncPhy sync_phy = CsSyncPhy::LE_2M_PHY; + std::array<uint8_t, 10> channel_map = GetChannelMap("1FFFFFFFFFFFFC7FFFFC"); + uint8_t channel_map_repetition = 1; // 0x01 to 0xFF + CsChannelSelectionType channel_selection_type = CsChannelSelectionType::TYPE_3C; + CsCh3cShape ch3c_shape = CsCh3cShape::HAT_SHAPE; + uint8_t ch3c_jump = 2; // 0x02 to 0x08 + uint8_t t_ip1_time = 0x0A; // 0x0A, 0x14, 0x1E, 0x28, 0x32, 0x3C, 0x50, or 0x91 + uint8_t t_ip2_time = 0x0A; // 0x0A, 0x14, 0x1E, 0x28, 0x32, 0x3C, 0x50, or 0x91 + uint8_t t_fcs_time = 0x0F; // 0x0F, 0x14, 0x1E, 0x28, 0x32, 0x3C, 0x50, 0x64, 0x78, or 0x96 + uint8_t t_pm_time = 0x0A; // 0x0A, 0x14, or 0x28 + + static const std::array<uint8_t, 10> GetChannelMap(const std::string& hex_string) { + assert(hex_stinrg.length() == 20); + auto channel_vector = common::FromHexString(hex_string); + std::array<uint8_t, 10> channel_map{}; + std::copy(channel_vector->begin(), channel_vector->end(), channel_map.begin()); + std::reverse(channel_map.begin(), channel_map.end()); + return channel_map; + } +}; + +struct CsProcedureEnableCompleteEvent { + ErrorCode status = ErrorCode::SUCCESS; + uint8_t config_id = 0; + uint8_t tone_antenna_config_selection = 0; + uint8_t selected_tx_power = 0; // -127 to 20 dBm + uint32_t subevent_len = 2500; // 1250us to 4s + uint8_t subevents_per_event = 1; // 0x01 to 0x20 + uint16_t subevent_interval = 1; // N x 0.625ms + uint16_t event_interval = 0; // number of acl conn interval + uint16_t procedure_interval = 2; // number of acl conn interval + uint16_t procedure_count = 5; // 0x0001 to 0xFFFF + uint16_t max_procedure_len = 10; // N x 0.625 ms +}; + struct StartMeasurementParameters { Address remote_address = Address::FromString("12:34:56:78:9a:bc").value(); uint16_t connection_handle = 64; @@ -126,6 +184,7 @@ protected: EXPECT_CALL(*mock_controller_, SupportsBleChannelSounding()).WillOnce(Return(true)); EXPECT_CALL(*mock_ranging_hal_, IsBound()).Times(AtLeast(1)).WillRepeatedly(Return(true)); + EXPECT_CALL(*mock_ranging_hal_, GetRangingHalVersion).WillRepeatedly(Return(hal::V_2)); handler_ = fake_registry_.GetTestHandler(); dm_manager_ = fake_registry_.Start<DistanceMeasurementManager>(&thread_, handler_); @@ -145,6 +204,19 @@ protected: return dm_session_promise_->get_future(); } + std::future<void> fake_timer_advance(uint64_t ms) { + std::promise<void> promise; + auto future = promise.get_future(); + handler_->Post(common::BindOnce( + [](std::promise<void> promise, uint64_t ms) { + fake_timerfd_advance(ms); + promise.set_value(); + }, + common::Passed(std::move(promise)), ms)); + + return future; + } + void sync_client_handler() { log::assert_that(thread_.GetReactor()->WaitForIdle(kTimeout), "assert failed: thread_.GetReactor()->WaitForIdle(kTimeout)"); @@ -172,6 +244,55 @@ protected: cs_cap_complete_event.t_sw_time_supported, cs_cap_complete_event.tx_snr_capability); } + static std::unique_ptr<LeCsReadRemoteSupportedCapabilitiesCompleteBuilder> + GetRemoteSupportedCapabilitiesCompleteEvent( + uint16_t connection_handle, + const CsReadCapabilitiesCompleteEvent& cs_cap_complete_event) { + return LeCsReadRemoteSupportedCapabilitiesCompleteBuilder::Create( + cs_cap_complete_event.error_code, connection_handle, + cs_cap_complete_event.num_config_supported, + cs_cap_complete_event.max_consecutive_procedures_supported, + cs_cap_complete_event.num_antennas_supported, + cs_cap_complete_event.max_antenna_paths_supported, + cs_cap_complete_event.roles_supported, cs_cap_complete_event.modes_supported, + cs_cap_complete_event.rtt_capability, cs_cap_complete_event.rtt_aa_only_n, + cs_cap_complete_event.rtt_sounding_n, cs_cap_complete_event.rtt_random_payload_n, + cs_cap_complete_event.nadm_sounding_capability, + cs_cap_complete_event.nadm_random_capability, + cs_cap_complete_event.cs_sync_phys_supported, + cs_cap_complete_event.subfeatures_supported, + cs_cap_complete_event.t_ip1_times_supported, + cs_cap_complete_event.t_ip2_times_supported, + cs_cap_complete_event.t_fcs_times_supported, cs_cap_complete_event.t_pm_times_supported, + cs_cap_complete_event.t_sw_time_supported, cs_cap_complete_event.tx_snr_capability); + } + + static std::unique_ptr<LeCsConfigCompleteBuilder> GetConfigCompleteEvent( + uint16_t connection_handle, CsConfigCompleteEvent complete_event) { + return LeCsConfigCompleteBuilder::Create( + complete_event.status, connection_handle, complete_event.config_id, + complete_event.action, complete_event.main_mode_type, complete_event.sub_mode_type, + complete_event.min_main_mode_steps, complete_event.max_main_mode_steps, + complete_event.main_mode_repetition, complete_event.mode_0_steps, + complete_event.cs_role, complete_event.rtt_type, complete_event.sync_phy, + complete_event.channel_map, complete_event.channel_map_repetition, + complete_event.channel_selection_type, complete_event.ch3c_shape, + complete_event.ch3c_jump, complete_event.t_ip1_time, complete_event.t_ip2_time, + complete_event.t_fcs_time, complete_event.t_pm_time); + } + + static std::unique_ptr<LeCsProcedureEnableCompleteBuilder> GetProcedureEnableCompleteEvent( + uint16_t connection_handle, Enable enable, + CsProcedureEnableCompleteEvent complete_event) { + return LeCsProcedureEnableCompleteBuilder::Create( + complete_event.status, connection_handle, complete_event.config_id, enable, + complete_event.tone_antenna_config_selection, complete_event.selected_tx_power, + complete_event.subevent_len, complete_event.subevents_per_event, + complete_event.subevent_interval, complete_event.event_interval, + complete_event.procedure_interval, complete_event.procedure_count, + complete_event.max_procedure_len); + } + void StartMeasurement(const StartMeasurementParameters& params) { dm_manager_->StartDistanceMeasurement(params.remote_address, params.connection_handle, params.local_hci_role, params.interval, params.method); @@ -183,6 +304,72 @@ protected: GetLocalSupportedCapabilitiesCompleteEvent(read_cs_complete_event)); } + void StartMeasurementTillRasConnectedEvent(const StartMeasurementParameters& params) { + ReceivedReadLocalCapabilitiesComplete(); + EXPECT_CALL(*mock_ranging_hal_, OpenSession(_, _, _)) + .WillOnce([this](uint16_t connection_handle, uint16_t /*att_handle*/, + const std::vector<hal::VendorSpecificCharacteristic>& + vendor_specific_data) { + mock_ranging_hal_->GetRangingHalCallback()->OnOpened(connection_handle, + vendor_specific_data); + }); + StartMeasurement(params); + dm_manager_->HandleRasClientConnectedEvent( + params.remote_address, params.connection_handle, + /*att_handle=*/0, + /*vendor_specific_data=*/std::vector<hal::VendorSpecificCharacteristic>(), + /*conn_interval=*/24); + } + + void StartMeasurementTillReadRemoteCaps(const StartMeasurementParameters& params) { + StartMeasurementTillRasConnectedEvent(params); + + test_hci_layer_->GetCommand(OpCode::LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES); + CsReadCapabilitiesCompleteEvent read_cs_complete_event; + test_hci_layer_->IncomingEvent(LeCsReadRemoteSupportedCapabilitiesStatusBuilder::Create( + /*status=*/ErrorCode::SUCCESS, + /*num_hci_command_packets=*/0xFF)); + test_hci_layer_->IncomingLeMetaEvent(GetRemoteSupportedCapabilitiesCompleteEvent( + params.connection_handle, read_cs_complete_event)); + + test_hci_layer_->GetCommand(OpCode::LE_CS_SET_DEFAULT_SETTINGS); + test_hci_layer_->IncomingEvent(LeCsSetDefaultSettingsCompleteBuilder::Create( + /*num_hci_command_packets=*/static_cast<uint8_t>(0xEE), ErrorCode::SUCCESS, + params.connection_handle)); + } + + void StartMeasurementTillCreateConfig(const StartMeasurementParameters& params) { + StartMeasurementTillReadRemoteCaps(params); + + CsConfigCompleteEvent cs_config_complete_event; + test_hci_layer_->GetCommand(OpCode::LE_CS_CREATE_CONFIG); + test_hci_layer_->IncomingEvent(LeCsCreateConfigStatusBuilder::Create( + /*status=*/ErrorCode::SUCCESS, + /*num_hci_command_packets=*/0xFF)); + test_hci_layer_->IncomingLeMetaEvent( + GetConfigCompleteEvent(params.connection_handle, cs_config_complete_event)); + } + + void StartMeasurementTillSecurityEnable(const StartMeasurementParameters& params) { + StartMeasurementTillCreateConfig(params); + + test_hci_layer_->GetCommand(OpCode::LE_CS_SECURITY_ENABLE); + test_hci_layer_->IncomingEvent(LeCsSecurityEnableStatusBuilder::Create( + /*status=*/ErrorCode::SUCCESS, + /*num_hci_command_packets=*/0xFF)); + test_hci_layer_->IncomingLeMetaEvent(LeCsSecurityEnableCompleteBuilder::Create( + ErrorCode::SUCCESS, params.connection_handle)); + } + + void StartMeasurementTillSetProcedureParameters(const StartMeasurementParameters& params) { + StartMeasurementTillSecurityEnable(params); + + test_hci_layer_->GetCommand(OpCode::LE_CS_SET_PROCEDURE_PARAMETERS); + test_hci_layer_->IncomingEvent(LeCsSetProcedureParametersCompleteBuilder::Create( + /*num_hci_command_packets=*/static_cast<uint8_t>(0xEE), ErrorCode::SUCCESS, + params.connection_handle)); + } + protected: TestModuleRegistry fake_registry_; HciLayerFake* test_hci_layer_ = nullptr; @@ -250,6 +437,193 @@ TEST_F(DistanceMeasurementManagerTest, ras_remote_not_support) { dm_session_future.wait_for(kTimeout); sync_client_handler(); } + +TEST_F(DistanceMeasurementManagerTest, error_read_remote_cs_caps_command) { + auto dm_session_future = GetDmSessionFuture(); + StartMeasurementParameters params; + StartMeasurementTillRasConnectedEvent(params); + + EXPECT_CALL(mock_dm_callbacks_, + OnDistanceMeasurementStopped(params.remote_address, + DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR, + DistanceMeasurementMethod::METHOD_CS)) + .WillOnce([this](const Address& /*address*/, DistanceMeasurementErrorCode /*error_code*/, + DistanceMeasurementMethod /*method*/) { + ASSERT_NE(dm_session_promise_, nullptr); + dm_session_promise_->set_value(); + dm_session_promise_.reset(); + }); + + test_hci_layer_->GetCommand(OpCode::LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES); + test_hci_layer_->IncomingEvent(LeCsReadRemoteSupportedCapabilitiesStatusBuilder::Create( + /*status=*/ErrorCode::COMMAND_DISALLOWED, + /*num_hci_command_packets=*/0xff)); + sync_client_handler(); +} + +TEST_F(DistanceMeasurementManagerTest, fail_read_remote_cs_caps_complete) { + auto dm_session_future = GetDmSessionFuture(); + StartMeasurementParameters params; + StartMeasurementTillRasConnectedEvent(params); + + EXPECT_CALL(mock_dm_callbacks_, + OnDistanceMeasurementStopped(params.remote_address, + DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR, + DistanceMeasurementMethod::METHOD_CS)) + .WillOnce([this](const Address& /*address*/, DistanceMeasurementErrorCode /*error_code*/, + DistanceMeasurementMethod /*method*/) { + ASSERT_NE(dm_session_promise_, nullptr); + dm_session_promise_->set_value(); + dm_session_promise_.reset(); + }); + + test_hci_layer_->GetCommand(OpCode::LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES); + CsReadCapabilitiesCompleteEvent read_cs_complete_event; + read_cs_complete_event.error_code = ErrorCode::COMMAND_DISALLOWED; + test_hci_layer_->IncomingLeMetaEvent(GetRemoteSupportedCapabilitiesCompleteEvent( + params.connection_handle, read_cs_complete_event)); + sync_client_handler(); +} + +TEST_F(DistanceMeasurementManagerTest, error_create_config_command) { + auto dm_session_future = GetDmSessionFuture(); + StartMeasurementParameters params; + StartMeasurementTillReadRemoteCaps(params); + + EXPECT_CALL(mock_dm_callbacks_, + OnDistanceMeasurementStopped(params.remote_address, + DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR, + DistanceMeasurementMethod::METHOD_CS)) + .WillOnce([this](const Address& /*address*/, DistanceMeasurementErrorCode /*error_code*/, + DistanceMeasurementMethod /*method*/) { + ASSERT_NE(dm_session_promise_, nullptr); + dm_session_promise_->set_value(); + dm_session_promise_.reset(); + }); + + test_hci_layer_->GetCommand(OpCode::LE_CS_CREATE_CONFIG); + test_hci_layer_->IncomingEvent(LeCsCreateConfigStatusBuilder::Create( + /*status=*/ErrorCode::COMMAND_DISALLOWED, + /*num_hci_command_packets=*/0xff)); + sync_client_handler(); +} + +TEST_F(DistanceMeasurementManagerTest, fail_create_config_complete) { + auto dm_session_future = GetDmSessionFuture(); + StartMeasurementParameters params; + StartMeasurementTillReadRemoteCaps(params); + + EXPECT_CALL(mock_dm_callbacks_, + OnDistanceMeasurementStopped(params.remote_address, + DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR, + DistanceMeasurementMethod::METHOD_CS)) + .WillOnce([this](const Address& /*address*/, DistanceMeasurementErrorCode /*error_code*/, + DistanceMeasurementMethod /*method*/) { + ASSERT_NE(dm_session_promise_, nullptr); + dm_session_promise_->set_value(); + dm_session_promise_.reset(); + }); + + CsConfigCompleteEvent cs_config_complete_event; + cs_config_complete_event.status = ErrorCode::COMMAND_DISALLOWED; + for (int i = 0; i <= kMaxRetryCounterForCreateConfig; i++) { + test_hci_layer_->GetCommand(OpCode::LE_CS_CREATE_CONFIG); + test_hci_layer_->IncomingLeMetaEvent( + GetConfigCompleteEvent(params.connection_handle, cs_config_complete_event)); + } + sync_client_handler(); +} + +TEST_F(DistanceMeasurementManagerTest, retry_fail_procedure_enable_command) { + auto dm_session_future = GetDmSessionFuture(); + StartMeasurementParameters params; + StartMeasurementTillSetProcedureParameters(params); + + EXPECT_CALL(mock_dm_callbacks_, + OnDistanceMeasurementStopped(params.remote_address, + DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR, + DistanceMeasurementMethod::METHOD_CS)) + .WillOnce([this](const Address& /*address*/, DistanceMeasurementErrorCode /*error_code*/, + DistanceMeasurementMethod /*method*/) { + ASSERT_NE(dm_session_promise_, nullptr); + dm_session_promise_->set_value(); + dm_session_promise_.reset(); + }); + + for (int i = 0; i <= kMaxRetryCounterForCsEnable; i++) { + test_hci_layer_->GetCommand(OpCode::LE_CS_PROCEDURE_ENABLE); + test_hci_layer_->IncomingEvent(LeCsProcedureEnableStatusBuilder::Create( + /*status=*/ErrorCode::COMMAND_DISALLOWED, + /*num_hci_command_packets=*/0xff)); + auto future = fake_timer_advance(params.interval + 10); + future.wait_for(kTimeout); + sync_client_handler(); + } + fake_timerfd_reset(); + sync_client_handler(); +} + +TEST_F(DistanceMeasurementManagerTest, retry_fail_procedure_enable_complete) { + auto dm_session_future = GetDmSessionFuture(); + StartMeasurementParameters params; + StartMeasurementTillSetProcedureParameters(params); + + EXPECT_CALL(mock_dm_callbacks_, + OnDistanceMeasurementStopped(params.remote_address, + DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR, + DistanceMeasurementMethod::METHOD_CS)) + .WillOnce([this](const Address& /*address*/, DistanceMeasurementErrorCode /*error_code*/, + DistanceMeasurementMethod /*method*/) { + ASSERT_NE(dm_session_promise_, nullptr); + dm_session_promise_->set_value(); + dm_session_promise_.reset(); + }); + + CsProcedureEnableCompleteEvent complete_event; + complete_event.status = ErrorCode::LINK_LAYER_COLLISION; + for (int i = 0; i <= kMaxRetryCounterForCsEnable; i++) { + test_hci_layer_->GetCommand(OpCode::LE_CS_PROCEDURE_ENABLE); + test_hci_layer_->IncomingEvent(LeCsProcedureEnableStatusBuilder::Create( + /*status=*/ErrorCode::SUCCESS, + /*num_hci_command_packets=*/0xff)); + test_hci_layer_->IncomingLeMetaEvent(GetProcedureEnableCompleteEvent( + params.connection_handle, Enable::ENABLED, complete_event)); + auto future = fake_timer_advance(params.interval + 10); + future.wait_for(kTimeout); + sync_client_handler(); + } + fake_timerfd_reset(); + sync_client_handler(); +} + +TEST_F(DistanceMeasurementManagerTest, unexpected_procedure_enable_complete_as_disable) { + auto dm_session_future = GetDmSessionFuture(); + StartMeasurementParameters params; + StartMeasurementTillSetProcedureParameters(params); + + EXPECT_CALL(mock_dm_callbacks_, + OnDistanceMeasurementStopped(params.remote_address, + DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR, + DistanceMeasurementMethod::METHOD_CS)) + .WillOnce([this](const Address& /*address*/, DistanceMeasurementErrorCode /*error_code*/, + DistanceMeasurementMethod /*method*/) { + ASSERT_NE(dm_session_promise_, nullptr); + dm_session_promise_->set_value(); + dm_session_promise_.reset(); + }); + + test_hci_layer_->GetCommand(OpCode::LE_CS_PROCEDURE_ENABLE); + test_hci_layer_->IncomingEvent(LeCsProcedureEnableStatusBuilder::Create( + /*status=*/ErrorCode::SUCCESS, + /*num_hci_command_packets=*/0xff)); + CsProcedureEnableCompleteEvent complete_event; + complete_event.status = ErrorCode::LINK_LAYER_COLLISION; + test_hci_layer_->IncomingLeMetaEvent(GetProcedureEnableCompleteEvent( + params.connection_handle, Enable::DISABLED, complete_event)); + + sync_client_handler(); +} + } // namespace } // namespace hci } // namespace bluetooth diff --git a/system/gd/hci/hci_layer.cc b/system/gd/hci/hci_layer.cc index 85d8af092e..da370a7564 100644 --- a/system/gd/hci/hci_layer.cc +++ b/system/gd/hci/hci_layer.cc @@ -64,6 +64,11 @@ using std::unique_ptr; static std::recursive_mutex life_cycle_guard; static bool life_cycle_stopped = true; +#ifdef TARGET_FLOSS +// Signal to indicate the controller needs to be reset. +const int SIG_RESET_CTRL = SIGUSR1; +#endif + static std::chrono::milliseconds getHciTimeoutMs() { static auto sHciTimeoutMs = std::chrono::milliseconds(bluetooth::os::GetSystemPropertyUint32Base( "bluetooth.hci.timeout_milliseconds", HciLayer::kHciTimeoutMs.count())); @@ -296,12 +301,18 @@ struct HciLayer::impl { void on_hci_timeout(OpCode op_code) { #ifdef TARGET_FLOSS + std::unique_lock<std::recursive_mutex> lock(life_cycle_guard); + if (life_cycle_stopped) { + return; + } + log::warn("Ignoring the timeouted HCI command {}.", OpCodeText(op_code)); - // Terminate the process to trigger controller reset, also mark the controller - // is broken to prevent further error while terminating. - auto hal = module_.GetDependency<hal::HciHal>(); - hal->markControllerBroken(); - kill(getpid(), SIGTERM); + + // Terminate the process to trigger controller reset, also stop sending and + // processing any incoming packet immediately to prevent further error + // while terminating. + module_.LifeCycleStop(); + kill(getpid(), SIG_RESET_CTRL); return; #endif @@ -507,12 +518,11 @@ struct HciLayer::impl { log::assert_that(event_view.IsValid(), "assert failed: event_view.IsValid()"); #ifdef TARGET_FLOSS log::warn("Hardware Error Event with code 0x{:02x}", event_view.GetHardwareCode()); - // Sending SIGTERM to process the exception from BT controller. + // Sending signal to indicate BT controller needs to reset. // The Floss daemon will be restarted. HCI reset during restart will clear the // error state of the BT controller. - auto hal = module_.GetDependency<hal::HciHal>(); - hal->markControllerBroken(); - kill(getpid(), SIGTERM); + module_.LifeCycleStop(); + kill(getpid(), SIG_RESET_CTRL); #else log::fatal("Hardware Error Event with code 0x{:02x}", event_view.GetHardwareCode()); #endif @@ -619,6 +629,14 @@ struct HciLayer::hal_callbacks : public hal::HciHalCallbacks { module_.impl_->incoming_iso_buffer_.Enqueue(std::move(iso), module_.GetHandler()); } +#ifdef TARGET_FLOSS + void controllerNeedsReset() override { + log::info("Controller needs reset!"); + module_.LifeCycleStop(); + kill(getpid(), SIG_RESET_CTRL); + } +#endif + HciLayer& module_; }; @@ -958,6 +976,7 @@ void HciLayer::StartWithNoHalDependencies(Handler* handler) { void HciLayer::Stop() { std::unique_lock<std::recursive_mutex> lock(life_cycle_guard); + life_cycle_stopped = true; auto hal = GetDependency<hal::HciHal>(); hal->unregisterIncomingPacketCallback(); delete hal_callbacks_; @@ -966,7 +985,11 @@ void HciLayer::Stop() { impl_->sco_queue_.GetDownEnd()->UnregisterDequeue(); impl_->iso_queue_.GetDownEnd()->UnregisterDequeue(); delete impl_; +} +// Function to stop sending and handling incoming packets +void HciLayer::LifeCycleStop() { + std::unique_lock<std::recursive_mutex> lock(life_cycle_guard); life_cycle_stopped = true; } diff --git a/system/gd/hci/hci_layer.h b/system/gd/hci/hci_layer.h index 7f894b2de6..94f706cf6b 100644 --- a/system/gd/hci/hci_layer.h +++ b/system/gd/hci/hci_layer.h @@ -149,6 +149,8 @@ protected: void Stop() override; + void LifeCycleStop(); + virtual void Disconnect(uint16_t handle, ErrorCode reason); virtual void ReadRemoteVersion(hci::ErrorCode hci_status, uint16_t handle, uint8_t version, uint16_t manufacturer_name, uint16_t sub_version); diff --git a/system/gd/hci/le_address_manager.cc b/system/gd/hci/le_address_manager.cc index 804f88985e..327ea0f0ca 100644 --- a/system/gd/hci/le_address_manager.cc +++ b/system/gd/hci/le_address_manager.cc @@ -165,12 +165,8 @@ void LeAddressManager::SetPrivacyPolicyForInitiatorAddress( min_seconds.count(), max_seconds.count()); enqueue_command_.Run(std::move(packet)); } else { - if (com::android::bluetooth::flags::non_wake_alarm_for_rpa_rotation()) { - address_rotation_wake_alarm_ = std::make_unique<os::Alarm>(handler_, true); - address_rotation_non_wake_alarm_ = std::make_unique<os::Alarm>(handler_, false); - } else { - address_rotation_wake_alarm_ = std::make_unique<os::Alarm>(handler_); - } + address_rotation_wake_alarm_ = std::make_unique<os::Alarm>(handler_, true); + address_rotation_non_wake_alarm_ = std::make_unique<os::Alarm>(handler_, false); } set_random_address(); break; @@ -229,12 +225,8 @@ void LeAddressManager::SetPrivacyPolicyForInitiatorAddressForTest( min_seconds.count(), max_seconds.count()); enqueue_command_.Run(std::move(packet)); } else { - if (com::android::bluetooth::flags::non_wake_alarm_for_rpa_rotation()) { - address_rotation_wake_alarm_ = std::make_unique<os::Alarm>(handler_, true); - address_rotation_non_wake_alarm_ = std::make_unique<os::Alarm>(handler_, false); - } else { - address_rotation_wake_alarm_ = std::make_unique<os::Alarm>(handler_); - } + address_rotation_wake_alarm_ = std::make_unique<os::Alarm>(handler_, true); + address_rotation_non_wake_alarm_ = std::make_unique<os::Alarm>(handler_, false); set_random_address(); } break; @@ -422,31 +414,25 @@ void LeAddressManager::prepare_to_rotate() { } void LeAddressManager::schedule_rotate_random_address() { - if (com::android::bluetooth::flags::non_wake_alarm_for_rpa_rotation()) { - std::string client_name = "LeAddressManager"; - auto privateAddressIntervalRange = GetNextPrivateAddressIntervalRange(client_name); - address_rotation_wake_alarm_->Schedule( - common::BindOnce( - []() { log::info("deadline wakeup in schedule_rotate_random_address"); }), - privateAddressIntervalRange.max); - address_rotation_non_wake_alarm_->Schedule( - common::BindOnce(&LeAddressManager::prepare_to_rotate, common::Unretained(this)), - privateAddressIntervalRange.min); - - auto now = std::chrono::system_clock::now(); - if (address_rotation_interval_min.has_value()) { - CheckAddressRotationHappenedInExpectedTimeInterval( - *address_rotation_interval_min, *address_rotation_interval_max, now, client_name); - } - - // Update the expected range here. - address_rotation_interval_min.emplace(now + privateAddressIntervalRange.min); - address_rotation_interval_max.emplace(now + privateAddressIntervalRange.max); - } else { - address_rotation_wake_alarm_->Schedule( - common::BindOnce(&LeAddressManager::prepare_to_rotate, common::Unretained(this)), - GetNextPrivateAddressIntervalMs()); + std::string client_name = "LeAddressManager"; + auto privateAddressIntervalRange = GetNextPrivateAddressIntervalRange(client_name); + address_rotation_wake_alarm_->Schedule( + common::BindOnce( + []() { log::info("deadline wakeup in schedule_rotate_random_address"); }), + privateAddressIntervalRange.max); + address_rotation_non_wake_alarm_->Schedule( + common::BindOnce(&LeAddressManager::prepare_to_rotate, common::Unretained(this)), + privateAddressIntervalRange.min); + + auto now = std::chrono::system_clock::now(); + if (address_rotation_interval_min.has_value()) { + CheckAddressRotationHappenedInExpectedTimeInterval( + *address_rotation_interval_min, *address_rotation_interval_max, now, client_name); } + + // Update the expected range here. + address_rotation_interval_min.emplace(now + privateAddressIntervalRange.min); + address_rotation_interval_max.emplace(now + privateAddressIntervalRange.max); } void LeAddressManager::set_random_address() { diff --git a/system/gd/hci/le_advertising_manager.cc b/system/gd/hci/le_advertising_manager.cc index f9a80f44f8..d626b2ee15 100644 --- a/system/gd/hci/le_advertising_manager.cc +++ b/system/gd/hci/le_advertising_manager.cc @@ -374,39 +374,29 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb log::info("Reenable advertising"); if (was_rotating_address) { log::info("Scheduling address rotation for advertiser_id={}", advertiser_id); - if (com::android::bluetooth::flags::non_wake_alarm_for_rpa_rotation()) { - advertising_sets_[advertiser_id].address_rotation_wake_alarm_ = - std::make_unique<os::Alarm>(module_handler_, true); - advertising_sets_[advertiser_id].address_rotation_non_wake_alarm_ = - std::make_unique<os::Alarm>(module_handler_, false); - - std::string client_name = "advertising_set_" + std::to_string(advertiser_id); - auto privateAddressIntervalRange = - le_address_manager_->GetNextPrivateAddressIntervalRange(client_name); - - advertising_sets_[advertiser_id].address_rotation_wake_alarm_->Schedule( - common::BindOnce( - []() { log::info("deadline wakeup in handle_set_terminated"); }), - privateAddressIntervalRange.max); - advertising_sets_[advertiser_id].address_rotation_non_wake_alarm_->Schedule( - common::BindOnce(&impl::set_advertising_set_random_address_on_timer, - common::Unretained(this), advertiser_id), - privateAddressIntervalRange.min); - - // Update the expected range here. - auto now = std::chrono::system_clock::now(); - advertising_sets_[advertiser_id].address_rotation_interval_min.emplace( - now + privateAddressIntervalRange.min); - advertising_sets_[advertiser_id].address_rotation_interval_max.emplace( - now + privateAddressIntervalRange.max); - } else { - advertising_sets_[advertiser_id].address_rotation_wake_alarm_ = - std::make_unique<os::Alarm>(module_handler_); - advertising_sets_[advertiser_id].address_rotation_wake_alarm_->Schedule( - common::BindOnce(&impl::set_advertising_set_random_address_on_timer, - common::Unretained(this), advertiser_id), - le_address_manager_->GetNextPrivateAddressIntervalMs()); - } + advertising_sets_[advertiser_id].address_rotation_wake_alarm_ = + std::make_unique<os::Alarm>(module_handler_, true); + advertising_sets_[advertiser_id].address_rotation_non_wake_alarm_ = + std::make_unique<os::Alarm>(module_handler_, false); + + std::string client_name = "advertising_set_" + std::to_string(advertiser_id); + auto privateAddressIntervalRange = + le_address_manager_->GetNextPrivateAddressIntervalRange(client_name); + + advertising_sets_[advertiser_id].address_rotation_wake_alarm_->Schedule( + common::BindOnce([]() { log::info("deadline wakeup in handle_set_terminated"); }), + privateAddressIntervalRange.max); + advertising_sets_[advertiser_id].address_rotation_non_wake_alarm_->Schedule( + common::BindOnce(&impl::set_advertising_set_random_address_on_timer, + common::Unretained(this), advertiser_id), + privateAddressIntervalRange.min); + + // Update the expected range here. + auto now = std::chrono::system_clock::now(); + advertising_sets_[advertiser_id].address_rotation_interval_min.emplace( + now + privateAddressIntervalRange.min); + advertising_sets_[advertiser_id].address_rotation_interval_max.emplace( + now + privateAddressIntervalRange.max); } enable_advertiser(advertiser_id, true, 0, 0); } @@ -673,40 +663,31 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb !leaudio_requested_nrpa && (!controller_->IsRpaGenerationSupported())) { // start timer for random address log::info("Scheduling address rotation for advertiser_id={}", id); - if (com::android::bluetooth::flags::non_wake_alarm_for_rpa_rotation()) { - advertising_sets_[id].address_rotation_wake_alarm_ = - std::make_unique<os::Alarm>(module_handler_, true); - advertising_sets_[id].address_rotation_non_wake_alarm_ = - std::make_unique<os::Alarm>(module_handler_, false); - - std::string client_name = "advertising_set_" + std::to_string(id); - auto privateAddressIntervalRange = - le_address_manager_->GetNextPrivateAddressIntervalRange(client_name); - - advertising_sets_[id].address_rotation_wake_alarm_->Schedule( - common::BindOnce([]() { - log::info("deadline wakeup in create_extended_advertiser_with_id"); - }), - privateAddressIntervalRange.max); - advertising_sets_[id].address_rotation_non_wake_alarm_->Schedule( - common::BindOnce(&impl::set_advertising_set_random_address_on_timer, - common::Unretained(this), id), - privateAddressIntervalRange.min); - - // Update the expected range here. - auto now = std::chrono::system_clock::now(); - advertising_sets_[id].address_rotation_interval_min.emplace( - now + privateAddressIntervalRange.min); - advertising_sets_[id].address_rotation_interval_max.emplace( - now + privateAddressIntervalRange.max); - } else { - advertising_sets_[id].address_rotation_wake_alarm_ = - std::make_unique<os::Alarm>(module_handler_); - advertising_sets_[id].address_rotation_wake_alarm_->Schedule( - common::BindOnce(&impl::set_advertising_set_random_address_on_timer, - common::Unretained(this), id), - le_address_manager_->GetNextPrivateAddressIntervalMs()); - } + advertising_sets_[id].address_rotation_wake_alarm_ = + std::make_unique<os::Alarm>(module_handler_, true); + advertising_sets_[id].address_rotation_non_wake_alarm_ = + std::make_unique<os::Alarm>(module_handler_, false); + + std::string client_name = "advertising_set_" + std::to_string(id); + auto privateAddressIntervalRange = + le_address_manager_->GetNextPrivateAddressIntervalRange(client_name); + + advertising_sets_[id].address_rotation_wake_alarm_->Schedule( + common::BindOnce([]() { + log::info("deadline wakeup in create_extended_advertiser_with_id"); + }), + privateAddressIntervalRange.max); + advertising_sets_[id].address_rotation_non_wake_alarm_->Schedule( + common::BindOnce(&impl::set_advertising_set_random_address_on_timer, + common::Unretained(this), id), + privateAddressIntervalRange.min); + + // Update the expected range here. + auto now = std::chrono::system_clock::now(); + advertising_sets_[id].address_rotation_interval_min.emplace( + now + privateAddressIntervalRange.min); + advertising_sets_[id].address_rotation_interval_max.emplace( + now + privateAddressIntervalRange.max); } } if (config.advertising_type == AdvertisingType::ADV_IND || @@ -859,39 +840,31 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb } log::info("Scheduling address rotation for advertiser_id={}", advertiser_id); - if (com::android::bluetooth::flags::non_wake_alarm_for_rpa_rotation()) { - std::string client_name = "advertising_set_" + std::to_string(advertiser_id); - auto privateAddressIntervalRange = - le_address_manager_->GetNextPrivateAddressIntervalRange(client_name); - advertising_sets_[advertiser_id].address_rotation_wake_alarm_->Schedule( - common::BindOnce([]() { - log::info("deadline wakeup in set_advertising_set_random_address_on_timer"); - }), - privateAddressIntervalRange.max); - advertising_sets_[advertiser_id].address_rotation_non_wake_alarm_->Schedule( - common::BindOnce(&impl::set_advertising_set_random_address_on_timer, - common::Unretained(this), advertiser_id), - privateAddressIntervalRange.min); - - auto now = std::chrono::system_clock::now(); - if (advertising_sets_[advertiser_id].address_rotation_interval_min.has_value()) { - le_address_manager_->CheckAddressRotationHappenedInExpectedTimeInterval( - *(advertising_sets_[advertiser_id].address_rotation_interval_min), - *(advertising_sets_[advertiser_id].address_rotation_interval_max), now, - client_name); - } - - // Update the expected range here. - advertising_sets_[advertiser_id].address_rotation_interval_min.emplace( - now + privateAddressIntervalRange.min); - advertising_sets_[advertiser_id].address_rotation_interval_max.emplace( - now + privateAddressIntervalRange.max); - } else { - advertising_sets_[advertiser_id].address_rotation_wake_alarm_->Schedule( - common::BindOnce(&impl::set_advertising_set_random_address_on_timer, - common::Unretained(this), advertiser_id), - le_address_manager_->GetNextPrivateAddressIntervalMs()); + std::string client_name = "advertising_set_" + std::to_string(advertiser_id); + auto privateAddressIntervalRange = + le_address_manager_->GetNextPrivateAddressIntervalRange(client_name); + advertising_sets_[advertiser_id].address_rotation_wake_alarm_->Schedule( + common::BindOnce([]() { + log::info("deadline wakeup in set_advertising_set_random_address_on_timer"); + }), + privateAddressIntervalRange.max); + advertising_sets_[advertiser_id].address_rotation_non_wake_alarm_->Schedule( + common::BindOnce(&impl::set_advertising_set_random_address_on_timer, + common::Unretained(this), advertiser_id), + privateAddressIntervalRange.min); + + auto now = std::chrono::system_clock::now(); + if (advertising_sets_[advertiser_id].address_rotation_interval_min.has_value()) { + le_address_manager_->CheckAddressRotationHappenedInExpectedTimeInterval( + *(advertising_sets_[advertiser_id].address_rotation_interval_min), + *(advertising_sets_[advertiser_id].address_rotation_interval_max), now, client_name); } + + // Update the expected range here. + advertising_sets_[advertiser_id].address_rotation_interval_min.emplace( + now + privateAddressIntervalRange.min); + advertising_sets_[advertiser_id].address_rotation_interval_max.emplace( + now + privateAddressIntervalRange.max); } void register_advertiser( diff --git a/system/gd/metrics/chromeos/OWNERS b/system/gd/metrics/chromeos/OWNERS deleted file mode 100644 index a823e6e1dd..0000000000 --- a/system/gd/metrics/chromeos/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_chromeos diff --git a/system/gd/metrics/counter_metrics.h b/system/gd/metrics/counter_metrics.h index 88c7711f92..2f25f03ed0 100644 --- a/system/gd/metrics/counter_metrics.h +++ b/system/gd/metrics/counter_metrics.h @@ -15,6 +15,8 @@ */ #pragma once +#include <com_android_bluetooth_flags.h> + #include <unordered_map> #include "module.h" @@ -26,6 +28,13 @@ namespace metrics { class CounterMetrics : public bluetooth::Module { public: CounterMetrics(os::Handler* handler) : Module(handler) {} + ~CounterMetrics() { + if (!com::android::bluetooth::flags::same_handler_for_all_modules()) { + GetHandler()->Clear(); + GetHandler()->WaitUntilStopped(std::chrono::milliseconds(2000)); + delete GetHandler(); + } + } bool CacheCount(int32_t key, int64_t value); virtual bool Count(int32_t key, int64_t count); diff --git a/system/gd/metrics/linux/OWNERS b/system/gd/metrics/linux/OWNERS deleted file mode 100644 index a823e6e1dd..0000000000 --- a/system/gd/metrics/linux/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_chromeos diff --git a/system/gd/module.cc b/system/gd/module.cc index 8904f0c559..76b386bbfe 100644 --- a/system/gd/module.cc +++ b/system/gd/module.cc @@ -128,10 +128,18 @@ void ModuleRegistry::StopAll() { auto module = Get(*it); last_instance_ = "stopping " + module->ToString(); - // Clear the handler before stopping the module to allow it to shut down gracefully. - log::info("Stopping Handler of Module {}", module->ToString()); - module->handler_->Clear(); - module->handler_->WaitUntilStopped(kModuleStopTimeout); + /* + * b/393449774 since we have now shifted to a single handler for all modules, we don't need + * to clear the handler here, it will be done in the respective teardown. + * Since we have a single handler, we need to make sure that the handler instance is deleted + * only once, otherwise we will see a crash as a handler can only be cleared once. + */ + if (!com::android::bluetooth::flags::same_handler_for_all_modules()) { + // Clear the handler before stopping the module to allow it to shut down gracefully. + log::info("Stopping Handler of Module {}", module->ToString()); + module->handler_->Clear(); + module->handler_->WaitUntilStopped(kModuleStopTimeout); + } log::info("Stopping Module {}", module->ToString()); module->Stop(); } @@ -144,7 +152,9 @@ void ModuleRegistry::StopAll() { auto instance = started_modules_.find(*it); log::assert_that(instance != started_modules_.end(), "assert failed: instance != started_modules_.end()"); - delete instance->second->handler_; + if (!com::android::bluetooth::flags::same_handler_for_all_modules()) { + delete instance->second->handler_; + } delete instance->second; started_modules_.erase(instance); } @@ -165,4 +175,15 @@ os::Handler* ModuleRegistry::GetModuleHandler(const ModuleFactory* module) const return nullptr; } +// Override the StopAll method to use the test thread and handler. +// This function will take care of releasing the handler instances. +void TestModuleRegistry::StopAll() { + os::Handler* handler = GetTestHandler(); + handler->Clear(); + if (com::android::bluetooth::flags::same_handler_for_all_modules()) { + handler->WaitUntilStopped(kHandlerStopTimeout); + } + ModuleRegistry::StopAll(); // call the base class StopAll + delete handler; +} } // namespace bluetooth diff --git a/system/gd/module.h b/system/gd/module.h index 816d455482..57e4db7d16 100644 --- a/system/gd/module.h +++ b/system/gd/module.h @@ -32,6 +32,9 @@ #include "os/thread.h" namespace bluetooth { +// Timeout for waiting for a handler to stop, used in Handler::WaitUntilStopped() +constexpr std::chrono::milliseconds kHandlerStopTimeout = std::chrono::milliseconds(2000); + namespace shim { class Stack; } // namespace shim @@ -191,6 +194,9 @@ public: os::Thread& GetTestThread() { return test_thread; } os::Handler* GetTestHandler() { return test_handler_; } + // Override the StopAll method to use the test thread and handler. + void StopAll(); + bool SynchronizeModuleHandler(const ModuleFactory* module, std::chrono::milliseconds timeout) const { return SynchronizeHandler(GetTestModuleHandler(module), timeout); diff --git a/system/gd/module_unittest.cc b/system/gd/module_unittest.cc index d1bf59ac73..8fb140c229 100644 --- a/system/gd/module_unittest.cc +++ b/system/gd/module_unittest.cc @@ -22,6 +22,7 @@ #include <sstream> #include <string> +#include "com_android_bluetooth_flags.h" #include "gtest/gtest.h" #include "os/handler.h" #include "os/thread.h" @@ -41,9 +42,12 @@ protected: void TearDown() override { handler_->Clear(); + if (com::android::bluetooth::flags::same_handler_for_all_modules()) { + handler_->WaitUntilStopped(kHandlerStopTimeout); + } delete registry_; - delete thread_; delete handler_; + delete thread_; } ModuleRegistry* registry_; diff --git a/system/gd/os/android/metrics.cc b/system/gd/os/android/metrics.cc index 78b12c8d96..5f5b34ef2e 100644 --- a/system/gd/os/android/metrics.cc +++ b/system/gd/os/android/metrics.cc @@ -122,11 +122,9 @@ void LogMetricRemoteVersionInfo(uint16_t handle, uint8_t status, uint8_t version manufacturer_name, subversion); if (ret < 0) { log::warn( - "Failed for handle {}, status {}, version {}, manufacturer_name {}, subversion {}, " - "error " - "{}", - handle, common::ToHexString(status), common::ToHexString(version), - common::ToHexString(manufacturer_name), common::ToHexString(subversion), ret); + "failed for handle {}, status 0x{:x}, version 0x{:x}, " + "manufacturer_name 0x{:x}, subversion 0x{:x}, error {}", + handle, status, version, manufacturer_name, subversion, ret); } } @@ -526,5 +524,53 @@ void LogMetricRfcommConnectionAtClose(const Address& address, } } +void LogMetricLeAudioConnectionSessionReported( + int32_t group_size, int32_t group_metric_id, int64_t connection_duration_nanos, + const std::vector<int64_t>& device_connecting_offset_nanos, + const std::vector<int64_t>& device_connected_offset_nanos, + const std::vector<int64_t>& device_connection_duration_nanos, + const std::vector<int32_t>& device_connection_status, + const std::vector<int32_t>& device_disconnection_status, + const std::vector<RawAddress>& device_address, + const std::vector<int64_t>& streaming_offset_nanos, + const std::vector<int64_t>& streaming_duration_nanos, + const std::vector<int32_t>& streaming_context_type) { + std::vector<int32_t> device_metric_id(device_address.size()); + for (uint64_t i = 0; i < device_address.size(); i++) { + if (!device_address[i].IsEmpty()) { + device_metric_id[i] = + MetricIdManager::GetInstance().AllocateId(ToGdAddress(device_address[i])); + } else { + device_metric_id[i] = 0; + } + } + int ret = stats_write(LE_AUDIO_CONNECTION_SESSION_REPORTED, group_size, group_metric_id, + connection_duration_nanos, device_connecting_offset_nanos, + device_connected_offset_nanos, device_connection_duration_nanos, + device_connection_status, device_disconnection_status, device_metric_id, + streaming_offset_nanos, streaming_duration_nanos, streaming_context_type); + if (ret < 0) { + log::warn( + "failed for group {}device_connecting_offset_nanos[{}], " + "device_connected_offset_nanos[{}], " + "device_connection_duration_nanos[{}], device_connection_status[{}], " + "device_disconnection_status[{}], device_metric_id[{}], " + "streaming_offset_nanos[{}], streaming_duration_nanos[{}], " + "streaming_context_type[{}]", + group_metric_id, device_connecting_offset_nanos.size(), + device_connected_offset_nanos.size(), device_connection_duration_nanos.size(), + device_connection_status.size(), device_disconnection_status.size(), + device_metric_id.size(), streaming_offset_nanos.size(), streaming_duration_nanos.size(), + streaming_context_type.size()); + } +} + +void LogMetricLeAudioBroadcastSessionReported(int64_t duration_nanos) { + int ret = stats_write(LE_AUDIO_BROADCAST_SESSION_REPORTED, duration_nanos); + if (ret < 0) { + log::warn("failed for duration={}", duration_nanos); + } +} + } // namespace os } // namespace bluetooth diff --git a/system/gd/os/chromeos/metrics.cc b/system/gd/os/chromeos/metrics.cc index b7921fe308..de36a98780 100644 --- a/system/gd/os/chromeos/metrics.cc +++ b/system/gd/os/chromeos/metrics.cc @@ -216,5 +216,19 @@ void LogMetricRfcommConnectionAtClose( android::bluetooth::BtaStatus /* sdp_status */, bool /* is_server */, bool /* sdp_initiated */, int32_t /* sdp_duration_ms */) {} +void LogMetricLeAudioConnectionSessionReported( + int32_t /*group_size*/, int32_t /*group_metric_id*/, int64_t /*connection_duration_nanos*/, + const std::vector<int64_t>& /*device_connecting_offset_nanos*/, + const std::vector<int64_t>& /*device_connected_offset_nanos*/, + const std::vector<int64_t>& /*device_connection_duration_nanos*/, + const std::vector<int32_t>& /*device_connection_status*/, + const std::vector<int32_t>& /*device_disconnection_status*/, + const std::vector<RawAddress>& /*device_address*/, + const std::vector<int64_t>& /*streaming_offset_nanos*/, + const std::vector<int64_t>& /*streaming_duration_nanos*/, + const std::vector<int32_t>& /*streaming_context_type*/) {} + +void LogMetricLeAudioBroadcastSessionReported(int64_t /*duration_nanos*/) {} + } // namespace os } // namespace bluetooth diff --git a/system/gd/os/host/metrics.cc b/system/gd/os/host/metrics.cc index a333113238..518a29ffee 100644 --- a/system/gd/os/host/metrics.cc +++ b/system/gd/os/host/metrics.cc @@ -135,5 +135,19 @@ void LogMetricRfcommConnectionAtClose( android::bluetooth::BtaStatus /* sdp_status */, bool /* is_server */, bool /* sdp_initiated */, int32_t /* sdp_duration_ms */) {} +void LogMetricLeAudioConnectionSessionReported( + int32_t /*group_size*/, int32_t /*group_metric_id*/, int64_t /*connection_duration_nanos*/, + const std::vector<int64_t>& /*device_connecting_offset_nanos*/, + const std::vector<int64_t>& /*device_connected_offset_nanos*/, + const std::vector<int64_t>& /*device_connection_duration_nanos*/, + const std::vector<int32_t>& /*device_connection_status*/, + const std::vector<int32_t>& /*device_disconnection_status*/, + const std::vector<RawAddress>& /*device_address*/, + const std::vector<int64_t>& /*streaming_offset_nanos*/, + const std::vector<int64_t>& /*streaming_duration_nanos*/, + const std::vector<int32_t>& /*streaming_context_type*/) {} + +void LogMetricLeAudioBroadcastSessionReported(int64_t /*duration_nanos*/) {} + } // namespace os } // namespace bluetooth diff --git a/system/gd/os/linux/metrics.cc b/system/gd/os/linux/metrics.cc index 7b727f38f2..f5d1555075 100644 --- a/system/gd/os/linux/metrics.cc +++ b/system/gd/os/linux/metrics.cc @@ -122,5 +122,20 @@ void LogMetricRfcommConnectionAtClose(const Address& raw_address, void LogMetricBluetoothEvent(const Address& address, android::bluetooth::EventType event_type, android::bluetooth::State state) {} + +void LogMetricLeAudioConnectionSessionReported( + int32_t /*group_size*/, int32_t /*group_metric_id*/, int64_t /*connection_duration_nanos*/, + const std::vector<int64_t>& /*device_connecting_offset_nanos*/, + const std::vector<int64_t>& /*device_connected_offset_nanos*/, + const std::vector<int64_t>& /*device_connection_duration_nanos*/, + const std::vector<int32_t>& /*device_connection_status*/, + const std::vector<int32_t>& /*device_disconnection_status*/, + const std::vector<RawAddress>& /*device_address*/, + const std::vector<int64_t>& /*streaming_offset_nanos*/, + const std::vector<int64_t>& /*streaming_duration_nanos*/, + const std::vector<int32_t>& /*streaming_context_type*/) {} + +void LogMetricLeAudioBroadcastSessionReported(int64_t /*duration_nanos*/) {} + } // namespace os } // namespace bluetooth diff --git a/system/gd/os/linux_generic/alarm.cc b/system/gd/os/linux_generic/alarm.cc index 8846ede579..a378ca93cd 100644 --- a/system/gd/os/linux_generic/alarm.cc +++ b/system/gd/os/linux_generic/alarm.cc @@ -17,7 +17,6 @@ #include "os/alarm.h" #include <bluetooth/log.h> -#include <com_android_bluetooth_flags.h> #include <sys/timerfd.h> #include <unistd.h> @@ -41,8 +40,7 @@ using common::OnceClosure; Alarm::Alarm(Handler* handler) : Alarm(handler, true) {} Alarm::Alarm(Handler* handler, bool isWakeAlarm) : handler_(handler) { - int timerfd_flag = - com::android::bluetooth::flags::non_wake_alarm_for_rpa_rotation() ? TFD_NONBLOCK : 0; + int timerfd_flag = TFD_NONBLOCK; fd_ = TIMERFD_CREATE(isWakeAlarm ? ALARM_CLOCK : CLOCK_BOOTTIME, timerfd_flag); @@ -85,7 +83,7 @@ void Alarm::on_fire() { auto bytes_read = read(fd_, ×_invoked, sizeof(uint64_t)); lock.unlock(); - if (com::android::bluetooth::flags::non_wake_alarm_for_rpa_rotation() && bytes_read == -1) { + if (bytes_read == -1) { log::debug("No data to read."); if (errno == EAGAIN || errno == EWOULDBLOCK) { log::debug("Alarm is already canceled or rescheduled."); diff --git a/system/gd/os/metrics.h b/system/gd/os/metrics.h index aab82826e6..04b5c37e84 100644 --- a/system/gd/os/metrics.h +++ b/system/gd/os/metrics.h @@ -29,8 +29,8 @@ #include "types/raw_address.h" namespace bluetooth { - namespace os { + /** * Unknown connection handle for metrics purpose */ @@ -379,6 +379,19 @@ void LogMetricRfcommConnectionAtClose(const hci::Address& address, android::bluetooth::BtaStatus sdp_status, bool is_server, bool sdp_initiated, int32_t sdp_duration_ms); +void LogMetricLeAudioConnectionSessionReported( + int32_t group_size, int32_t group_metric_id, int64_t connection_duration_nanos, + const std::vector<int64_t>& device_connecting_offset_nanos, + const std::vector<int64_t>& device_connected_offset_nanos, + const std::vector<int64_t>& device_connection_duration_nanos, + const std::vector<int32_t>& device_connection_status, + const std::vector<int32_t>& device_disconnection_status, + const std::vector<RawAddress>& device_address, + const std::vector<int64_t>& streaming_offset_nanos, + const std::vector<int64_t>& streaming_duration_nanos, + const std::vector<int32_t>& streaming_context_type); + +void LogMetricLeAudioBroadcastSessionReported(int64_t duration_nanos); + } // namespace os - // } // namespace bluetooth diff --git a/system/gd/rust/linux/OWNERS b/system/gd/rust/linux/OWNERS deleted file mode 100644 index a823e6e1dd..0000000000 --- a/system/gd/rust/linux/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_chromeos diff --git a/system/gd/rust/linux/service/src/interface_manager.rs b/system/gd/rust/linux/service/src/interface_manager.rs index 116979de0d..62fdbc8638 100644 --- a/system/gd/rust/linux/service/src/interface_manager.rs +++ b/system/gd/rust/linux/service/src/interface_manager.rs @@ -1,27 +1,29 @@ -use dbus::{channel::MatchingReceiver, message::MatchRule, nonblock::SyncConnection}; +use dbus::channel::MatchingReceiver; +use dbus::message::MatchRule; +use dbus::nonblock::SyncConnection; use dbus_crossroads::Crossroads; use dbus_projection::DisconnectWatcher; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc::{channel, Receiver, Sender}; -use btstack::{ - battery_manager::BatteryManager, battery_provider_manager::BatteryProviderManager, - bluetooth::Bluetooth, bluetooth_admin::BluetoothAdmin, bluetooth_gatt::BluetoothGatt, - bluetooth_logging::BluetoothLogging, bluetooth_media::BluetoothMedia, - bluetooth_qa::BluetoothQA, socket_manager::BluetoothSocketManager, suspend::Suspend, - APIMessage, BluetoothAPI, Message, -}; +use btstack::battery_manager::BatteryManager; +use btstack::battery_provider_manager::BatteryProviderManager; +use btstack::bluetooth::{Bluetooth, SigData}; +use btstack::bluetooth_admin::BluetoothAdmin; +use btstack::bluetooth_gatt::BluetoothGatt; +use btstack::bluetooth_logging::BluetoothLogging; +use btstack::bluetooth_media::BluetoothMedia; +use btstack::bluetooth_qa::BluetoothQA; +use btstack::socket_manager::BluetoothSocketManager; +use btstack::suspend::Suspend; +use btstack::{APIMessage, BluetoothAPI}; -use crate::iface_battery_manager; -use crate::iface_battery_provider_manager; -use crate::iface_bluetooth; -use crate::iface_bluetooth_admin; -use crate::iface_bluetooth_gatt; -use crate::iface_bluetooth_media; -use crate::iface_bluetooth_qa; -use crate::iface_bluetooth_telephony; -use crate::iface_logging; +use crate::{ + iface_battery_manager, iface_battery_provider_manager, iface_bluetooth, iface_bluetooth_admin, + iface_bluetooth_gatt, iface_bluetooth_media, iface_bluetooth_qa, iface_bluetooth_telephony, + iface_logging, +}; pub(crate) struct InterfaceManager {} @@ -50,11 +52,11 @@ impl InterfaceManager { #[allow(clippy::too_many_arguments)] pub async fn dispatch( mut rx: Receiver<APIMessage>, - tx: Sender<Message>, virt_index: i32, conn: Arc<SyncConnection>, conn_join_handle: tokio::task::JoinHandle<()>, disconnect_watcher: Arc<Mutex<DisconnectWatcher>>, + sig_notifier: Arc<SigData>, bluetooth: Arc<Mutex<Box<Bluetooth>>>, bluetooth_admin: Arc<Mutex<Box<BluetoothAdmin>>>, bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, @@ -93,6 +95,9 @@ impl InterfaceManager { }), ); + *sig_notifier.api_enabled.lock().unwrap() = true; + sig_notifier.api_notify.notify_all(); + // Register D-Bus method handlers of IBluetooth. let adapter_iface = iface_bluetooth::export_bluetooth_dbus_intf( conn.clone(), @@ -246,11 +251,8 @@ impl InterfaceManager { // To shut down the connection, call _handle.abort() and drop the connection. conn_join_handle.abort(); drop(conn); - - let tx = tx.clone(); - tokio::spawn(async move { - let _ = tx.send(Message::AdapterShutdown).await; - }); + *sig_notifier.api_enabled.lock().unwrap() = false; + sig_notifier.api_notify.notify_all(); break; } } diff --git a/system/gd/rust/linux/service/src/main.rs b/system/gd/rust/linux/service/src/main.rs index f326bb62ee..4fc43d11f3 100644 --- a/system/gd/rust/linux/service/src/main.rs +++ b/system/gd/rust/linux/service/src/main.rs @@ -9,22 +9,21 @@ use std::time::Duration; use tokio::runtime::Builder; use tokio::sync::mpsc::Sender; -use bt_topshim::{btif::get_btinterface, topstack}; -use btstack::{ - battery_manager::BatteryManager, - battery_provider_manager::BatteryProviderManager, - battery_service::BatteryService, - bluetooth::{Bluetooth, IBluetooth, SigData}, - bluetooth_admin::BluetoothAdmin, - bluetooth_gatt::BluetoothGatt, - bluetooth_logging::BluetoothLogging, - bluetooth_media::BluetoothMedia, - bluetooth_qa::BluetoothQA, - dis::DeviceInformation, - socket_manager::BluetoothSocketManager, - suspend::Suspend, - Message, Stack, -}; +use bt_topshim::btif::get_btinterface; +use bt_topshim::topstack; +use btstack::battery_manager::BatteryManager; +use btstack::battery_provider_manager::BatteryProviderManager; +use btstack::battery_service::BatteryService; +use btstack::bluetooth::{Bluetooth, IBluetooth, SigData}; +use btstack::bluetooth_admin::BluetoothAdmin; +use btstack::bluetooth_gatt::BluetoothGatt; +use btstack::bluetooth_logging::BluetoothLogging; +use btstack::bluetooth_media::BluetoothMedia; +use btstack::bluetooth_qa::BluetoothQA; +use btstack::dis::DeviceInformation; +use btstack::socket_manager::BluetoothSocketManager; +use btstack::suspend::Suspend; +use btstack::{Message, Stack}; mod dbus_arg; mod iface_battery_manager; @@ -40,6 +39,8 @@ mod interface_manager; const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth"; const ADMIN_SETTINGS_FILE_PATH: &str = "/var/lib/bluetooth/admin_policy.json"; +// Time to wait for API unregistration in DBus +const API_DISABLE_TIMEOUT_MS: Duration = Duration::from_millis(100); // The maximum ACL disconnect timeout is 3.5s defined by BTA_DM_DISABLE_TIMER_MS // and BTA_DM_DISABLE_TIMER_RETRIAL_MS const STACK_TURN_OFF_TIMEOUT_MS: Duration = Duration::from_millis(4000); @@ -115,6 +116,8 @@ fn main() -> Result<(), Box<dyn Error>> { enabled_notify: Condvar::new(), thread_attached: Mutex::new(false), thread_notify: Condvar::new(), + api_enabled: Mutex::new(false), + api_notify: Condvar::new(), }); // This needs to be built before any |topstack::get_runtime()| call! @@ -148,8 +151,14 @@ fn main() -> Result<(), Box<dyn Error>> { signal::SaFlags::empty(), signal::SigSet::empty(), ); + let sig_action_usr1 = signal::SigAction::new( + signal::SigHandler::Handler(handle_sigusr1), + signal::SaFlags::empty(), + signal::SigSet::empty(), + ); unsafe { signal::sigaction(signal::SIGTERM, &sig_action_term).unwrap(); + signal::sigaction(signal::SIGUSR1, &sig_action_usr1).unwrap(); } // Construct btstack profiles. @@ -241,11 +250,11 @@ fn main() -> Result<(), Box<dyn Error>> { tokio::spawn(interface_manager::InterfaceManager::dispatch( api_rx, - tx.clone(), virt_index, conn, conn_join_handle, disconnect_watcher.clone(), + sig_notifier.clone(), bluetooth.clone(), bluetooth_admin.clone(), bluetooth_gatt.clone(), @@ -267,37 +276,63 @@ fn main() -> Result<(), Box<dyn Error>> { /// Data needed for signal handling. static SIG_DATA: Mutex<Option<(Sender<Message>, Arc<SigData>)>> = Mutex::new(None); -extern "C" fn handle_sigterm(_signum: i32) { - let guard = SIG_DATA.lock().unwrap(); - if let Some((tx, notifier)) = guard.as_ref() { - log::debug!("Handling SIGTERM by disabling the adapter!"); - let txl = tx.clone(); - topstack::get_runtime().spawn(async move { - // Send the shutdown message here. - let _ = txl.send(Message::InterfaceShutdown).await; - }); +/// Try to cleanup the whole stack. Returns whether to clean up. +extern "C" fn try_cleanup_stack(abort: bool) -> bool { + let lock = SIG_DATA.try_lock(); + + // If SIG_DATA is locked, it is likely the cleanup procedure is ongoing. No + // need to do anything here. + if lock.is_err() { + return false; + } + + if let Some((tx, notifier)) = lock.unwrap().as_ref() { + log::info!("Cleanup stack: disabling the adapter!"); + + // Remove the API first to prevent clients calling while shutting down. + let guard = notifier.api_enabled.lock().unwrap(); + if *guard { + let txl = tx.clone(); + topstack::get_runtime().spawn(async move { + // Remove the API first to prevent clients calling while shutting down. + let _ = txl.send(Message::InterfaceShutdown).await; + }); + log::info!( + "Cleanup stack: Waiting for API shutdown to complete for {:?}", + API_DISABLE_TIMEOUT_MS + ); + let _ = notifier.api_notify.wait_timeout(guard, API_DISABLE_TIMEOUT_MS); + } let guard = notifier.enabled.lock().unwrap(); if *guard { - log::debug!("Waiting for stack to turn off for {:?}", STACK_TURN_OFF_TIMEOUT_MS); + let txl = tx.clone(); + topstack::get_runtime().spawn(async move { + let _ = txl.send(Message::AdapterShutdown(abort)).await; + }); + log::info!( + "Cleanup stack: Waiting for stack to turn off for {:?}", + STACK_TURN_OFF_TIMEOUT_MS + ); let _ = notifier.enabled_notify.wait_timeout(guard, STACK_TURN_OFF_TIMEOUT_MS); } - log::debug!("SIGTERM cleaning up the stack."); - let txl = tx.clone(); - topstack::get_runtime().spawn(async move { - // Clean up the profiles first as some of them might require main thread to clean up. - let _ = txl.send(Message::CleanupProfiles).await; - // Currently there is no good way to know when the profile is cleaned. - // Simply add a small delay here. - tokio::time::sleep(STACK_CLEANUP_PROFILES_TIMEOUT_MS).await; - // Send the cleanup message to clean up the main thread. - let _ = txl.send(Message::Cleanup).await; - }); - let guard = notifier.thread_attached.lock().unwrap(); if *guard { - log::debug!("Waiting for stack to clean up for {:?}", STACK_CLEANUP_TIMEOUT_MS); + let txl = tx.clone(); + topstack::get_runtime().spawn(async move { + // Clean up the profiles first as some of them might require main thread to clean up. + let _ = txl.send(Message::CleanupProfiles).await; + // Currently there is no good way to know when the profile is cleaned. + // Simply add a small delay here. + tokio::time::sleep(STACK_CLEANUP_PROFILES_TIMEOUT_MS).await; + // Send the cleanup message to clean up the main thread. + let _ = txl.send(Message::Cleanup).await; + }); + log::info!( + "Cleanup stack: Waiting for libbluetooth stack to clean up for {:?}", + STACK_CLEANUP_TIMEOUT_MS + ); let _ = notifier.thread_notify.wait_timeout(guard, STACK_CLEANUP_TIMEOUT_MS); } @@ -305,7 +340,26 @@ extern "C" fn handle_sigterm(_signum: i32) { // finishing btif cleanup. std::thread::sleep(EXTRA_WAIT_BEFORE_KILL_MS); } + return true; +} - log::debug!("Sigterm completed"); +extern "C" fn handle_sigterm(_signum: i32) { + log::info!("SIGTERM received"); + if !try_cleanup_stack(false) { + log::info!("Skipped to handle SIGTERM"); + return; + } + log::info!("SIGTERM completed"); + std::process::exit(0); +} + +/// Used to indicate controller needs reset +extern "C" fn handle_sigusr1(_signum: i32) { + log::info!("SIGUSR1 received"); + if !try_cleanup_stack(true) { + log::info!("Skipped to handle SIGUSR1"); + return; + } + log::info!("SIGUSR1 completed"); std::process::exit(0); } diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs index bac9c4a1a9..ade91229c4 100644 --- a/system/gd/rust/linux/stack/src/bluetooth.rs +++ b/system/gd/rust/linux/stack/src/bluetooth.rs @@ -503,6 +503,9 @@ pub struct SigData { pub thread_attached: Mutex<bool>, pub thread_notify: Condvar, + + pub api_enabled: Mutex<bool>, + pub api_notify: Condvar, } /// The interface for adapter callbacks registered through `IBluetooth::register_callback`. @@ -818,6 +821,21 @@ impl Bluetooth { self.connection_callbacks.remove_callback(id); } + pub fn shutdown_adapter(&mut self, abort: bool) -> bool { + self.disabling = true; + + if !abort { + if !self.set_discoverable(BtDiscMode::NonDiscoverable, 0) { + warn!("set_discoverable failed on disabling"); + } + if !self.set_connectable_internal(false) { + warn!("set_connectable_internal failed on disabling"); + } + } + + self.intf.lock().unwrap().disable() == 0 + } + fn get_remote_device_property( &self, device: &BluetoothDevice, @@ -2240,14 +2258,7 @@ impl IBluetooth for Bluetooth { } fn disable(&mut self) -> bool { - self.disabling = true; - if !self.set_discoverable(BtDiscMode::NonDiscoverable, 0) { - warn!("set_discoverable failed on disabling"); - } - if !self.set_connectable_internal(false) { - warn!("set_connectable_internal failed on disabling"); - } - self.intf.lock().unwrap().disable() == 0 + self.shutdown_adapter(false) } fn cleanup(&mut self) { diff --git a/system/gd/rust/linux/stack/src/lib.rs b/system/gd/rust/linux/stack/src/lib.rs index d9f97bfa32..4f49a186b4 100644 --- a/system/gd/rust/linux/stack/src/lib.rs +++ b/system/gd/rust/linux/stack/src/lib.rs @@ -66,7 +66,9 @@ pub enum Message { /// Remove the DBus API. Call it before other AdapterShutdown. InterfaceShutdown, /// Disable the adapter by calling btif disable. - AdapterShutdown, + /// Param: bool to indicate abort(true) or graceful shutdown(false). + /// Use abort when we believe adapter is already in a bad state. + AdapterShutdown(bool), /// Clean up the adapter by calling btif cleanup. Cleanup, /// Clean up the media by calling profile cleanup. @@ -287,9 +289,9 @@ impl Stack { }); } - Message::AdapterShutdown => { + Message::AdapterShutdown(abort) => { bluetooth_gatt.lock().unwrap().enable(false); - bluetooth.lock().unwrap().disable(); + bluetooth.lock().unwrap().shutdown_adapter(abort); } Message::Cleanup => { diff --git a/system/gd/rust/topshim/OWNERS b/system/gd/rust/topshim/OWNERS deleted file mode 100644 index a823e6e1dd..0000000000 --- a/system/gd/rust/topshim/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_chromeos diff --git a/system/gd/storage/storage_module.cc b/system/gd/storage/storage_module.cc index 5e3459e109..5a81a5cf94 100644 --- a/system/gd/storage/storage_module.cc +++ b/system/gd/storage/storage_module.cc @@ -90,6 +90,13 @@ StorageModule::StorageModule(os::Handler* handler, std::string config_file_path, StorageModule::~StorageModule() { std::lock_guard<std::recursive_mutex> lock(mutex_); + + if (!com::android::bluetooth::flags::same_handler_for_all_modules()) { + GetHandler()->Clear(); + GetHandler()->WaitUntilStopped(std::chrono::milliseconds(2000)); + delete GetHandler(); + } + pimpl_.reset(); } diff --git a/system/include/hardware/bluetooth_headset_interface.h b/system/include/hardware/bluetooth_headset_interface.h index b2b98ffe1f..396c2b2880 100644 --- a/system/include/hardware/bluetooth_headset_interface.h +++ b/system/include/hardware/bluetooth_headset_interface.h @@ -97,9 +97,10 @@ public: /** * Start voice recognition * @param bd_addr remote device address + * @param sendResult whether a BVRA response should be sent * @return BT_STATUS_SUCCESS on success */ - virtual bt_status_t StartVoiceRecognition(RawAddress* bd_addr) = 0; + virtual bt_status_t StartVoiceRecognition(RawAddress* bd_addr, bool sendResult) = 0; /** * Stop voice recognition diff --git a/system/linux_include/log/log.h b/system/linux_include/log/log.h deleted file mode 100644 index 037649312c..0000000000 --- a/system/linux_include/log/log.h +++ /dev/null @@ -1,24 +0,0 @@ -/****************************************************************************** - * - * Copyright 2018 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 - -#ifndef __ANDROID__ - -#include <cstdint> - -#endif diff --git a/system/log/OWNERS b/system/log/OWNERS deleted file mode 100644 index d1c75de900..0000000000 --- a/system/log/OWNERS +++ /dev/null @@ -1 +0,0 @@ -henrichataing@google.com diff --git a/system/main/shim/acl.cc b/system/main/shim/acl.cc index b2f0e23975..b01bd1f92d 100644 --- a/system/main/shim/acl.cc +++ b/system/main/shim/acl.cc @@ -969,11 +969,6 @@ struct shim::Acl::impl { maximum_latency, minimum_remote_timeout, minimum_local_timeout); } - void LeSetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t sup_tout) { - GetAclManager()->LeSetDefaultSubrate(subrate_min, subrate_max, max_latency, cont_num, sup_tout); - } - void LeSubrateRequest(HciHandle handle, uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t sup_tout) { if (IsLeAcl(handle)) { @@ -1573,12 +1568,6 @@ void shim::Acl::UpdateConnectionParameters(uint16_t handle, uint16_t conn_int_mi conn_int_max, conn_latency, conn_timeout, min_ce_len, max_ce_len); } -void shim::Acl::LeSetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, - uint16_t max_latency, uint16_t cont_num, uint16_t sup_tout) { - handler_->CallOn(pimpl_.get(), &Acl::impl::LeSetDefaultSubrate, subrate_min, subrate_max, - max_latency, cont_num, sup_tout); -} - void shim::Acl::LeSubrateRequest(uint16_t hci_handle, uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t sup_tout) { handler_->CallOn(pimpl_.get(), &Acl::impl::LeSubrateRequest, hci_handle, subrate_min, subrate_max, diff --git a/system/main/shim/acl.h b/system/main/shim/acl.h index bbe15d0acf..8253faf013 100644 --- a/system/main/shim/acl.h +++ b/system/main/shim/acl.h @@ -80,8 +80,6 @@ public: void RemoveFromAddressResolution(const hci::AddressWithType& address_with_type); void ClearAddressResolution(); - void LeSetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t sup_tout); void LeSubrateRequest(uint16_t hci_handle, uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t sup_tout); diff --git a/system/main/shim/acl_api.cc b/system/main/shim/acl_api.cc index 56e63e1977..0868f40f2c 100644 --- a/system/main/shim/acl_api.cc +++ b/system/main/shim/acl_api.cc @@ -166,12 +166,6 @@ void bluetooth::shim::ACL_ClearAddressResolution() { void bluetooth::shim::ACL_ClearFilterAcceptList() { Stack::GetInstance()->GetAcl()->ClearFilterAcceptList(); } -void bluetooth::shim::ACL_LeSetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, - uint16_t max_latency, uint16_t cont_num, - uint16_t sup_tout) { - Stack::GetInstance()->GetAcl()->LeSetDefaultSubrate(subrate_min, subrate_max, max_latency, - cont_num, sup_tout); -} void bluetooth::shim::ACL_LeSubrateRequest(uint16_t hci_handle, uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, diff --git a/system/main/shim/acl_api.h b/system/main/shim/acl_api.h index 6b28988ca6..b0bac16e02 100644 --- a/system/main/shim/acl_api.h +++ b/system/main/shim/acl_api.h @@ -49,8 +49,6 @@ void ACL_AddToAddressResolution(const tBLE_BD_ADDR& legacy_address_with_type, void ACL_RemoveFromAddressResolution(const tBLE_BD_ADDR& legacy_address_with_type); void ACL_ClearAddressResolution(); void ACL_ClearFilterAcceptList(); -void ACL_LeSetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t sup_tout); void ACL_SendConnectionParameterUpdateRequest(uint16_t handle, uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency, uint16_t conn_timeout, uint16_t min_ce_len, diff --git a/system/main/shim/stack.cc b/system/main/shim/stack.cc index bb8994aee0..027361875d 100644 --- a/system/main/shim/stack.cc +++ b/system/main/shim/stack.cc @@ -67,9 +67,9 @@ namespace shim { struct Stack::impl { Acl* acl_ = nullptr; - metrics::CounterMetrics* counter_metrics_ = nullptr; - storage::StorageModule* storage_ = nullptr; - hal::SnoopLogger* snoop_logger_ = nullptr; + std::shared_ptr<metrics::CounterMetrics> counter_metrics_ = nullptr; + std::shared_ptr<storage::StorageModule> storage_ = nullptr; + std::shared_ptr<hal::SnoopLogger> snoop_logger_ = nullptr; }; Stack::Stack() { pimpl_ = std::make_shared<Stack::impl>(); } @@ -89,9 +89,16 @@ void Stack::StartEverything() { stack_thread_ = new os::Thread("gd_stack_thread", os::Thread::Priority::REAL_TIME); stack_handler_ = new os::Handler(stack_thread_); - pimpl_->counter_metrics_ = new metrics::CounterMetrics(new Handler(stack_thread_)); - pimpl_->storage_ = new storage::StorageModule(new Handler(stack_thread_)); - pimpl_->snoop_logger_ = new hal::SnoopLogger(new Handler(stack_thread_)); + if (com::android::bluetooth::flags::same_handler_for_all_modules()) { + pimpl_->counter_metrics_ = std::make_shared<metrics::CounterMetrics>(stack_handler_); + pimpl_->storage_ = std::make_shared<storage::StorageModule>(stack_handler_); + pimpl_->snoop_logger_ = std::make_shared<hal::SnoopLogger>(stack_handler_); + } else { + pimpl_->counter_metrics_ = + std::make_shared<metrics::CounterMetrics>(new Handler(stack_thread_)); + pimpl_->storage_ = std::make_shared<storage::StorageModule>(new Handler(stack_thread_)); + pimpl_->snoop_logger_ = std::make_shared<hal::SnoopLogger>(new Handler(stack_thread_)); + } #if TARGET_FLOSS modules.add<sysprops::SyspropsModule>(); @@ -119,6 +126,7 @@ void Stack::StartEverything() { } is_running_ = true; + log::info("GD stack is running"); std::promise<void> promise; auto future = promise.get_future(); @@ -168,12 +176,13 @@ void Stack::Stop() { log::assert_that(is_running_, "Gd stack not running"); is_running_ = false; + log::info("GD stack is not running"); - if (!com::android::bluetooth::flags::same_handler_for_all_modules()) { - // Clear the handler only if the flag is not defined, otherwise it will be cleared by the - // registry - stack_handler_->Clear(); + stack_handler_->Clear(); + if(com::android::bluetooth::flags::same_handler_for_all_modules()) { + stack_handler_->WaitUntilStopped(bluetooth::kHandlerStopTimeout); } + WakelockManager::Get().Acquire(); std::promise<void> promise; @@ -195,14 +204,7 @@ void Stack::Stop() { delete management_handler_; delete management_thread_; - if (!com::android::bluetooth::flags::same_handler_for_all_modules()) { - // delete the handler only if the flag is not defined, otherwise it will be deleted by the - // registry - delete stack_handler_; - } - - // stack_handler_ is already deleted by the registry in handle_shut_down, just set it to nullptr - // to avoid any potential use-after-free + delete stack_handler_; stack_handler_ = nullptr; stack_thread_->Stop(); @@ -227,19 +229,19 @@ Acl* Stack::GetAcl() const { metrics::CounterMetrics* Stack::GetCounterMetrics() const { std::lock_guard<std::recursive_mutex> lock(mutex_); log::assert_that(is_running_, "assert failed: is_running_"); - return pimpl_->counter_metrics_; + return pimpl_->counter_metrics_.get(); } storage::StorageModule* Stack::GetStorage() const { std::lock_guard<std::recursive_mutex> lock(mutex_); log::assert_that(is_running_, "assert failed: is_running_"); - return pimpl_->storage_; + return pimpl_->storage_.get(); } hal::SnoopLogger* Stack::GetSnoopLogger() const { std::lock_guard<std::recursive_mutex> lock(mutex_); log::assert_that(is_running_, "assert failed: is_running_"); - return pimpl_->snoop_logger_; + return pimpl_->snoop_logger_.get(); } os::Handler* Stack::GetHandler() { @@ -275,9 +277,15 @@ void Stack::handle_start_up(ModuleList* modules, std::promise<void> promise) { void Stack::handle_shut_down(std::promise<void> promise) { registry_.StopAll(); + pimpl_->snoop_logger_->Stop(); pimpl_->storage_->Stop(); pimpl_->counter_metrics_->Stop(); + + pimpl_->snoop_logger_.reset(); + pimpl_->storage_.reset(); + pimpl_->counter_metrics_.reset(); + promise.set_value(); } diff --git a/system/main/test/main_shim_test.cc b/system/main/test/main_shim_test.cc index 2f4056a381..c66024cabb 100644 --- a/system/main/test/main_shim_test.cc +++ b/system/main/test/main_shim_test.cc @@ -332,8 +332,10 @@ protected: thread_ = new os::Thread("acl_thread", os::Thread::Priority::NORMAL); handler_ = new os::Handler(thread_); - /* extern */ test::mock_controller_ = new bluetooth::hci::testing::MockControllerInterface(); - /* extern */ test::mock_acl_manager_ = new bluetooth::hci::testing::MockAclManager(); + /* extern */ test::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); + /* extern */ test::mock_acl_manager_ = + std::make_unique<bluetooth::hci::testing::MockAclManager>(); /* extern */ test::mock_le_scanning_manager_ = new bluetooth::hci::testing::MockLeScanningManager(); /* extern */ test::mock_le_advertising_manager_ = @@ -342,10 +344,8 @@ protected: new bluetooth::hci::testing::MockDistanceMeasurementManager(); } void TearDown() override { - delete test::mock_controller_; - test::mock_controller_ = nullptr; - delete test::mock_acl_manager_; - test::mock_acl_manager_ = nullptr; + test::mock_controller_.reset(); + test::mock_acl_manager_.release(); delete test::mock_le_advertising_manager_; test::mock_le_advertising_manager_ = nullptr; delete test::mock_le_scanning_manager_; @@ -567,7 +567,6 @@ TEST_F(MainShimTest, DISABLED_BleScannerInterfaceImpl_OnScanResult) { bluetooth::shim::get_ble_scanner_instance()); EXPECT_CALL(*hci::testing::mock_le_scanning_manager_, RegisterScanningCallback(_)).Times(1); - ; bluetooth::shim::init_scanning_manager(); TestScanningCallbacks cb; diff --git a/system/osi/BUILD.gn b/system/osi/BUILD.gn index 5bdf04c1e9..fa47062f52 100644 --- a/system/osi/BUILD.gn +++ b/system/osi/BUILD.gn @@ -43,7 +43,6 @@ static_library("osi") { include_dirs = [ "//bt/system/", - "//bt/system/linux_include", "//bt/system/osi/include_internal", "//bt/system/stack/include", ] diff --git a/system/pdl/hci/hci_packets.pdl b/system/pdl/hci/hci_packets.pdl index fcdd255b99..838b1fa586 100644 --- a/system/pdl/hci/hci_packets.pdl +++ b/system/pdl/hci/hci_packets.pdl @@ -4949,7 +4949,8 @@ struct CsOptionalNadmRandomCapability { struct CsOptionalCsSyncPhysSupported { le_2m_phy : 1, - _reserved_ : 7, + le_2m_2bt_phy : 1, + _reserved_ : 6, } struct CsOptionalSubfeaturesSupported { @@ -5151,6 +5152,7 @@ enum CsConfigRttType : 8 { enum CsSyncPhy : 8 { LE_1M_PHY = 0x01, LE_2M_PHY = 0x02, + LE_2M_2BT_PHY = 0x03, } enum CsChannelSelectionType : 8 { diff --git a/system/stack/Android.bp b/system/stack/Android.bp index ebab1ff5f4..78af467a76 100644 --- a/system/stack/Android.bp +++ b/system/stack/Android.bp @@ -48,7 +48,6 @@ cc_library_static { "hid", "include", "l2cap", - "metrics", "pan", "sdp", "smp", @@ -183,7 +182,6 @@ cc_library_static { "l2cap/l2c_main.cc", "l2cap/l2c_utils.cc", "l2cap/l2cap_api.cc", - "metrics/stack_metrics_logging.cc", "pan/pan_api.cc", "pan/pan_main.cc", "pan/pan_utils.cc", @@ -374,9 +372,9 @@ cc_fuzz { ":TestFakeOsi", ":TestMockBtif", ":TestMockDevice", + ":TestMockMainShim", ":TestMockStackBtm", ":TestMockStackL2cap", - ":TestMockStackMetrics", "fuzzers/sdp_fuzzer.cc", ], static_libs: [ @@ -414,6 +412,7 @@ cc_fuzz { ":TestMockBtif", ":TestMockDevice", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockSrvcDis", ":TestMockStackAcl", @@ -421,7 +420,6 @@ cc_fuzz { ":TestMockStackBtm", ":TestMockStackHcic", ":TestMockStackL2cap", - ":TestMockStackMetrics", ":TestMockStackSdp", "fuzzers/rfcomm_fuzzer.cc", "rfcomm/*.cc", @@ -465,6 +463,7 @@ cc_fuzz { ":TestMockBtif", ":TestMockDevice", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockSrvcDis", ":TestMockStackAcl", @@ -473,7 +472,6 @@ cc_fuzz { ":TestMockStackConnMgr", ":TestMockStackHcic", ":TestMockStackL2cap", - ":TestMockStackMetrics", ":TestMockStackSdp", "ais/*.cc", "eatt/*.cc", @@ -517,12 +515,12 @@ cc_fuzz { ":TestMockBtif", ":TestMockDevice", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackAcl", ":TestMockStackBtm", ":TestMockStackHcic", ":TestMockStackL2cap", - ":TestMockStackMetrics", "fuzzers/smp_fuzzer.cc", "smp/*.cc", // add other sources files (p256 related) under smp into this test ], @@ -563,12 +561,12 @@ cc_fuzz { ":TestMockBtif", ":TestMockDevice", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackAcl", ":TestMockStackBtm", ":TestMockStackHcic", ":TestMockStackL2cap", - ":TestMockStackMetrics", "bnep/*.cc", "fuzzers/bnep_fuzzer.cc", ], @@ -601,12 +599,12 @@ cc_fuzz { ":TestMockBtif", ":TestMockDevice", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackAcl", ":TestMockStackBtm", ":TestMockStackHcic", ":TestMockStackL2cap", - ":TestMockStackMetrics", ":TestMockStackSdp", "avct/*.cc", "avrc/*.cc", @@ -648,11 +646,11 @@ cc_fuzz { ":TestMockBtif", ":TestMockDevice", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackAcl", ":TestMockStackBtm", ":TestMockStackHcic", - ":TestMockStackMetrics", "fuzzers/l2cap_fuzzer.cc", "l2cap/*.cc", ], @@ -809,10 +807,10 @@ cc_test { ":TestCommonMockFunctions", ":TestMockHci", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackBtm", ":TestMockStackL2capInterface", - ":TestMockStackMetrics", ":TestMockStackRfcommMetrics", "rfcomm/port_api.cc", "rfcomm/port_rfc.cc", @@ -903,12 +901,12 @@ cc_test { ":TestMockBtif", ":TestMockDevice", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackAcl", ":TestMockStackBtm", ":TestMockStackHcic", ":TestMockStackL2cap", - ":TestMockStackMetrics", "smp/p_256_curvepara.cc", "smp/p_256_ecc_pp.cc", "smp/p_256_multprecision.cc", @@ -1006,9 +1004,9 @@ cc_test { ":TestCommonMainHandler", ":TestCommonMockFunctions", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackBtm", - ":TestMockStackMetrics", "connection_manager/connection_manager.cc", "test/connection_manager_test.cc", ], @@ -1419,10 +1417,10 @@ cc_test { ":TestMockBtif", ":TestMockDevice", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockStackBtm", ":TestMockStackConnMgr", ":TestMockStackL2cap", - ":TestMockStackMetrics", "gatt/gatt_db.cc", "gatt/gatt_sr_hash.cc", "gatt/gatt_utils.cc", @@ -1675,7 +1673,6 @@ cc_test { "btm/hfp_msbc_decoder.cc", "btm/hfp_msbc_encoder.cc", "btm/security_event_parser.cc", - "metrics/stack_metrics_logging.cc", "test/btm/peer_packet_types_test.cc", "test/btm/sco_hci_test.cc", "test/btm/sco_pkt_status_test.cc", @@ -1813,9 +1810,9 @@ cc_test { ], srcs: [ ":TestCommonMockFunctions", + ":TestMockMainShim", ":TestMockStackBtm", ":TestMockStackL2cap", - ":TestMockStackMetrics", ":TestMockStackSdp", "hid/hidd_api.cc", "hid/hidd_conn.cc", @@ -1887,12 +1884,12 @@ cc_test { ":TestMockBtif", ":TestMockHci", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackAcl", ":TestMockStackBtm", ":TestMockStackHcic", ":TestMockStackL2cap", - ":TestMockStackMetrics", ":TestMockStackSmp", "btu/btu_hcif.cc", "btu/main_thread.cc", @@ -1964,12 +1961,12 @@ cc_test { ":TestMockBtif", ":TestMockHci", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockSrvcDis", ":TestMockStackAcl", ":TestMockStackBtm", ":TestMockStackL2cap", - ":TestMockStackMetrics", ":TestMockStackSdp", ":TestMockStackSmp", "ais/ais_ble.cc", @@ -2165,6 +2162,7 @@ cc_test { ":TestMockHci", ":TestMockLegacyHciInterface", ":TestMockMainShim", + ":TestMockMainShim", ":TestMockMainShimEntry", ":TestMockStackBtm", ":TestMockStackBtu", @@ -2172,7 +2170,6 @@ cc_test { ":TestMockStackGatt", ":TestMockStackHcic", ":TestMockStackL2cap", - ":TestMockStackMetrics", ":TestMockStackSdp", ":TestMockStackSmp", "acl/*.cc", @@ -2349,9 +2346,9 @@ cc_test { ":TestFakeOsi", ":TestMockBta", ":TestMockBtif", + ":TestMockMainShim", ":TestMockStackBtm", ":TestMockStackL2cap", - ":TestMockStackMetrics", "test/sdp/stack_sdp_api_test.cc", "test/sdp/stack_sdp_db_test.cc", "test/sdp/stack_sdp_parse_test.cc", diff --git a/system/stack/BUILD.gn b/system/stack/BUILD.gn index d078d1bc14..f06a098bd5 100644 --- a/system/stack/BUILD.gn +++ b/system/stack/BUILD.gn @@ -149,7 +149,6 @@ source_set("stack") { "l2cap/l2c_main.cc", "l2cap/l2c_utils.cc", "l2cap/l2cap_api.cc", - "metrics/stack_metrics_logging.cc", "pan/pan_api.cc", "pan/pan_main.cc", "pan/pan_utils.cc", @@ -210,7 +209,6 @@ source_set("stack") { "//bt/system/ctrlr/include", "//bt/system/gd", "//bt/system/hcis", - "//bt/system/linux_include", "//bt/system/rpc/include", "//bt/system/udrv/include", "//bt/system/vnd/ble", @@ -367,7 +365,6 @@ if (defined(use.android) && use.android) { include_dirs = [ "//bt/system/", - "//bt/system/linux_include", "//bt/system/bta/include", "//bt/system/bta/sys", "//bt/system/embdrv/sbc/encoder/include", diff --git a/system/stack/acl/btm_acl.cc b/system/stack/acl/btm_acl.cc index 69afab3bfa..1a4c292d55 100644 --- a/system/stack/acl/btm_acl.cc +++ b/system/stack/acl/btm_acl.cc @@ -41,7 +41,6 @@ #include "bta/gatt/bta_gattc_int.h" #include "bta/include/bta_dm_acl.h" #include "bta/sys/bta_sys.h" -#include "common/metrics.h" #include "device/include/device_iot_config.h" #include "device/include/interop.h" #include "hci/controller_interface.h" @@ -51,6 +50,7 @@ #include "main/shim/dumpsys.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" +#include "os/metrics.h" #include "os/parameter_provider.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" @@ -785,10 +785,10 @@ static void btm_process_remote_version_complete(uint8_t status, uint16_t handle, p_acl_cb->remote_version_info.valid = true; BTM_update_version_info(p_acl_cb->RemoteAddress(), p_acl_cb->remote_version_info); - bluetooth::common::LogRemoteVersionInfo(handle, status, lmp_version, manufacturer, - lmp_subversion); + bluetooth::os::LogMetricRemoteVersionInfo(handle, status, lmp_version, manufacturer, + lmp_subversion); } else { - bluetooth::common::LogRemoteVersionInfo(handle, status, 0, 0, 0); + bluetooth::os::LogMetricRemoteVersionInfo(handle, status, 0, 0, 0); } } diff --git a/system/stack/btm/btm_ble_sec.cc b/system/stack/btm/btm_ble_sec.cc index b7db7fa130..679e937eef 100644 --- a/system/stack/btm/btm_ble_sec.cc +++ b/system/stack/btm/btm_ble_sec.cc @@ -1621,8 +1621,16 @@ void btm_ble_connection_established(const RawAddress& bda) { !p_dev_rec->sec_rec.is_le_link_key_known())) { // Unknown device if (p_dev_rec->dev_class == kDevClassEmpty || p_dev_rec->dev_class == kDevClassUnclassified) { - // Class of device not known, read appearance characteristic - btm_ble_read_remote_cod(bda); + // Class of device not known, read appearance characteristic ... + // Unless it is one of those devices which don't respond to this request + BD_NAME remote_name = {}; + if (p_dev_rec->sec_rec.is_name_known() && BTM_GetRemoteDeviceName(bda, remote_name) && + interop_match_name(INTEROP_DISABLE_READ_LE_APPEARANCE, (const char*)remote_name)) { + log::warn("Name {} matches IOP database, not reading appearance for {}", + (const char*)remote_name, bda); + } else { + btm_ble_read_remote_cod(bda); + } } } } @@ -1654,6 +1662,13 @@ static bool btm_ble_complete_evt_ignore(const tBTM_SEC_DEV_REC* p_dev_rec, p_dev_rec->bd_addr); l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle); return true; + } else if (com::android::bluetooth::flags::le_peripheral_enc_failure() && + !p_dev_rec->role_central) { + log::warn("Peripheral encryption request failed for the bonded device {} with reason {}", + p_dev_rec->bd_addr, smp_status_text(p_data->complt.reason)); + btm_sec_disconnect(p_dev_rec->ble_hci_handle, HCI_ERR_AUTH_FAILURE, + smp_status_text(p_data->complt.reason)); + return true; } } @@ -1694,6 +1709,11 @@ static void btm_ble_complete_evt(const RawAddress& bd_addr, tBTM_SEC_DEV_REC* p_ } BTM_BLE_SEC_CALLBACK(BTM_LE_COMPLT_EVT, bd_addr, p_data); + p_dev_rec = btm_find_dev(bd_addr); // BTM_LE_COMPLT_EVT event may have removed the device + if (p_dev_rec == nullptr) { + log::warn("Device record removed {}", bd_addr); + return; + } log::verbose("before update sec_level=0x{:x} sec_flags=0x{:x}", p_data->complt.sec_level, p_dev_rec->sec_rec.sec_flags); diff --git a/system/stack/btm/btm_dev.cc b/system/stack/btm/btm_dev.cc index 92dc80e1ab..992a59236c 100644 --- a/system/stack/btm/btm_dev.cc +++ b/system/stack/btm/btm_dev.cc @@ -326,6 +326,10 @@ static bool is_handle_equal(void* data, void* context) { * ******************************************************************************/ tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t handle) { + if (handle == HCI_INVALID_HANDLE) { + return nullptr; + } + if (btm_sec_cb.sec_dev_rec == nullptr) { return nullptr; } @@ -335,7 +339,7 @@ tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t handle) { return static_cast<tBTM_SEC_DEV_REC*>(list_node(n)); } - return NULL; + return nullptr; } static bool is_not_same_identity_or_pseudo_address(void* data, void* context) { diff --git a/system/stack/btm/btm_sco.cc b/system/stack/btm/btm_sco.cc index c48b321448..82182135eb 100644 --- a/system/stack/btm/btm_sco.cc +++ b/system/stack/btm/btm_sco.cc @@ -44,6 +44,7 @@ #include "internal_include/bt_target.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" +#include "main/shim/metrics_api.h" #include "osi/include/properties.h" #include "osi/include/stack_power_telemetry.h" #include "stack/btm/btm_int_types.h" @@ -60,7 +61,6 @@ #include "stack/include/main_thread.h" #include "stack/include/sco_hci_link_interface.h" #include "stack/include/sdpdefs.h" -#include "stack/include/stack_metrics_logging.h" #include "types/raw_address.h" extern tBTM_CB btm_cb; @@ -1298,7 +1298,8 @@ static void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason) { if (fill_plc_stats(&num_decoded_frames, &packet_loss_ratio)) { const int16_t codec_id = sco_codec_type_to_id(codec_type); const std::string codec = sco_codec_type_text(codec_type); - log_hfp_audio_packet_loss_stats(bd_addr, num_decoded_frames, packet_loss_ratio, codec_id); + bluetooth::shim::LogMetricHfpPacketLossStats(bd_addr, num_decoded_frames, packet_loss_ratio, + codec_id); log::debug( "Stopped SCO codec:{}, num_decoded_frames:{}, " "packet_loss_ratio:{:f}", diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc index b00b779eee..4595794cab 100644 --- a/system/stack/btm/btm_sec.cc +++ b/system/stack/btm/btm_sec.cc @@ -38,7 +38,6 @@ #include "bta/dm/bta_dm_act.h" #include "bta/dm/bta_dm_sec_int.h" #include "btif/include/btif_storage.h" -#include "common/metrics.h" #include "common/time_util.h" #include "device/include/device_iot_config.h" #include "device/include/interop.h" @@ -47,7 +46,9 @@ #include "main/shim/acl_api.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" +#include "main/shim/metrics_api.h" #include "metrics/bluetooth_event.h" +#include "os/metrics.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" #include "stack/btm/btm_ble_int.h" @@ -75,7 +76,6 @@ #include "stack/include/main_thread.h" #include "stack/include/rnr_interface.h" #include "stack/include/smp_api.h" -#include "stack/include/stack_metrics_logging.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -1923,10 +1923,9 @@ static void btm_sec_bond_cancel_complete(void) { void btm_create_conn_cancel_complete(uint8_t status, const RawAddress bd_addr) { log::verbose("btm_create_conn_cancel_complete(): in State: {} status:{}", tBTM_SEC_CB::btm_pair_state_descr(btm_sec_cb.pairing_state), status); - log_link_layer_connection_event( - &bd_addr, bluetooth::common::kUnknownConnectionHandle, - android::bluetooth::DIRECTION_OUTGOING, android::bluetooth::LINK_TYPE_ACL, - android::bluetooth::hci::CMD_CREATE_CONNECTION_CANCEL, + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + &bd_addr, bluetooth::os::kUnknownConnectionHandle, android::bluetooth::DIRECTION_OUTGOING, + android::bluetooth::LINK_TYPE_ACL, android::bluetooth::hci::CMD_CREATE_CONNECTION_CANCEL, android::bluetooth::hci::EVT_COMMAND_COMPLETE, android::bluetooth::hci::BLE_EVT_UNKNOWN, status, android::bluetooth::hci::STATUS_UNKNOWN); @@ -2440,8 +2439,7 @@ void btm_io_capabilities_req(RawAddress p) { /* If device is bonded, and encrypted it's upgrading security and it's ok. * If it's bonded and not encrypted, it's remote missing keys scenario */ - if (!p_dev_rec->sec_rec.is_device_encrypted() && - com::android::bluetooth::flags::key_missing_classic_device()) { + if (!p_dev_rec->sec_rec.is_device_encrypted()) { log::warn("Incoming bond request, but {} is already bonded (notifying user)", p); bta_dm_remote_key_missing(p); btm_sec_disconnect(p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE, @@ -2632,8 +2630,7 @@ void btm_io_capabilities_rsp(const tBTM_SP_IO_RSP evt_data) { /* If device is bonded, and encrypted it's upgrading security and it's ok. * If it's bonded and not encrypted, it's remote missing keys scenario */ - if (btm_sec_is_a_bonded_dev(evt_data.bd_addr) && !p_dev_rec->sec_rec.is_device_encrypted() && - com::android::bluetooth::flags::key_missing_classic_device()) { + if (btm_sec_is_a_bonded_dev(evt_data.bd_addr) && !p_dev_rec->sec_rec.is_device_encrypted()) { log::warn("Incoming bond request, but {} is already bonded (notifying user)", evt_data.bd_addr); bta_dm_remote_key_missing(evt_data.bd_addr); btm_sec_disconnect(p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE, @@ -3031,8 +3028,7 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { p_dev_rec->sec_rec.classic_link, p_dev_rec->bd_addr, reinterpret_cast<char const*>(p_dev_rec->sec_bd_name)); - if (status == HCI_ERR_KEY_MISSING && - com::android::bluetooth::flags::key_missing_classic_device()) { + if (status == HCI_ERR_KEY_MISSING) { log::warn("auth_complete KEY_MISSING {} is already bonded (notifying user)", p_dev_rec->bd_addr); bta_dm_remote_key_missing(p_dev_rec->bd_addr); @@ -3133,12 +3129,12 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { p_dev_rec->sec_rec.security_required &= ~BTM_SEC_OUT_AUTHENTICATE; if (status != HCI_SUCCESS) { - if ((status != HCI_ERR_PEER_USER) && (status != HCI_ERR_CONN_CAUSE_LOCAL_HOST)) { + if (status != HCI_ERR_PEER_USER && status != HCI_ERR_CONN_CAUSE_LOCAL_HOST) { btm_sec_send_hci_disconnect( p_dev_rec, HCI_ERR_PEER_USER, p_dev_rec->hci_handle, "stack::btm::btm_sec::btm_sec_auth_retry Auth fail while bonding"); } - } else { + } else if (!com::android::bluetooth::flags::immediate_encryption_after_pairing()) { BTM_LogHistory(kBtmLogTag, p_dev_rec->bd_addr, "Bonding completed", hci_error_code_text(status)); @@ -3163,6 +3159,11 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) { } l2cu_start_post_bond_timer(p_dev_rec->hci_handle); + } else { + BTM_LogHistory(kBtmLogTag, p_dev_rec->bd_addr, "Bonding completed", + hci_error_code_text(status)); + BTM_SetEncryption(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, NULL, NULL, BTM_BLE_SEC_NONE); + l2cu_start_post_bond_timer(p_dev_rec->hci_handle); } return; @@ -3321,10 +3322,8 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, uint8_t encr_en if (status == HCI_ERR_KEY_MISSING) { log::info("Remote key missing - will report"); bta_dm_remote_key_missing(p_dev_rec->ble.pseudo_addr); - if (com::android::bluetooth::flags::sec_disconnect_on_le_key_missing()) { - btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_HOST_REJECT_SECURITY, - p_dev_rec->ble_hci_handle, "encryption_change:key_missing"); - } + btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_HOST_REJECT_SECURITY, + p_dev_rec->ble_hci_handle, "encryption_change:key_missing"); return; } diff --git a/system/stack/btm/security_event_parser.cc b/system/stack/btm/security_event_parser.cc index 84d7005d16..b107a69cb8 100644 --- a/system/stack/btm/security_event_parser.cc +++ b/system/stack/btm/security_event_parser.cc @@ -22,20 +22,19 @@ #include <string> #include "btm_sec.h" -#include "common/metrics.h" #include "hci/hci_packets.h" #include "main/shim/helpers.h" +#include "main/shim/metrics_api.h" +#include "os/metrics.h" #include "stack/include/btm_sec_api_types.h" #include "stack/include/hci_error_code.h" #include "stack/include/sec_hci_link_interface.h" -#include "stack/include/stack_metrics_logging.h" #include "types/raw_address.h" using namespace bluetooth; using namespace bluetooth::hci; using android::bluetooth::hci::CMD_UNKNOWN; using android::bluetooth::hci::STATUS_UNKNOWN; -using bluetooth::common::kUnknownConnectionHandle; namespace bluetooth::stack::btm { namespace { @@ -44,19 +43,19 @@ static void log_address_and_status(const Address& bda, EventCode event_code, uint32_t cmd = android::bluetooth::hci::CMD_UNKNOWN; uint16_t status = static_cast<uint16_t>(event_status); uint16_t reason = android::bluetooth::hci::STATUS_UNKNOWN; - uint16_t handle = bluetooth::common::kUnknownConnectionHandle; + uint16_t handle = bluetooth::os::kUnknownConnectionHandle; int64_t value = 0; - log_classic_pairing_event(ToRawAddress(bda), handle, cmd, static_cast<uint16_t>(event_code), - status, reason, value); + bluetooth::shim::LogMetricClassicPairingEvent( + ToRawAddress(bda), handle, cmd, static_cast<uint16_t>(event_code), status, reason, value); } static void log_address(const Address& bda, EventCode event_code) { uint32_t cmd = android::bluetooth::hci::CMD_UNKNOWN; uint16_t status = android::bluetooth::hci::STATUS_UNKNOWN; uint16_t reason = android::bluetooth::hci::STATUS_UNKNOWN; - uint16_t handle = bluetooth::common::kUnknownConnectionHandle; + uint16_t handle = bluetooth::os::kUnknownConnectionHandle; int64_t value = 0; - log_classic_pairing_event(ToRawAddress(bda), handle, cmd, static_cast<uint16_t>(event_code), - status, reason, value); + bluetooth::shim::LogMetricClassicPairingEvent( + ToRawAddress(bda), handle, cmd, static_cast<uint16_t>(event_code), status, reason, value); } static void parse_encryption_change(const EventView event) { auto change_opt = EncryptionChangeView::CreateOptional(event); @@ -69,7 +68,7 @@ static void parse_encryption_change(const EventView event) { btm_sec_encryption_change_evt(handle, static_cast<tHCI_STATUS>(status), static_cast<uint8_t>(encr_enable), 0); - log_classic_pairing_event( + bluetooth::shim::LogMetricClassicPairingEvent( ToRawAddress(Address::kEmpty), handle, android::bluetooth::hci::CMD_UNKNOWN, static_cast<uint32_t>(change.GetEventCode()), static_cast<uint16_t>(status), android::bluetooth::hci::STATUS_UNKNOWN, 0); @@ -86,7 +85,7 @@ static void parse_encryption_change_v2(const EventView event) { btm_sec_encryption_change_evt(handle, static_cast<tHCI_STATUS>(status), static_cast<uint8_t>(encr_enable), key_size); - log_classic_pairing_event( + bluetooth::shim::LogMetricClassicPairingEvent( ToRawAddress(Address::kEmpty), handle, android::bluetooth::hci::CMD_UNKNOWN, static_cast<uint32_t>(change.GetEventCode()), static_cast<uint16_t>(status), android::bluetooth::hci::STATUS_UNKNOWN, 0); @@ -96,7 +95,7 @@ static void parse_change_connection_link_key_complete(const EventView event) { log::assert_that(complete_opt.has_value(), "assert failed: complete_opt.has_value()"); auto complete = complete_opt.value(); - log_classic_pairing_event( + bluetooth::shim::LogMetricClassicPairingEvent( ToRawAddress(Address::kEmpty), complete.GetConnectionHandle(), android::bluetooth::hci::CMD_UNKNOWN, static_cast<uint32_t>(complete.GetEventCode()), static_cast<uint16_t>(complete.GetStatus()), android::bluetooth::hci::STATUS_UNKNOWN, 0); diff --git a/system/stack/btu/btu_hcif.cc b/system/stack/btu/btu_hcif.cc index 7a4b6d1256..367c8a89c8 100644 --- a/system/stack/btu/btu_hcif.cc +++ b/system/stack/btu/btu_hcif.cc @@ -37,9 +37,10 @@ #include <cstdint> #include "btm_iso_api.h" -#include "common/metrics.h" #include "internal_include/bt_target.h" #include "main/shim/hci_layer.h" +#include "main/shim/metrics_api.h" +#include "os/metrics.h" #include "osi/include/allocator.h" #include "stack/include/acl_api.h" #include "stack/include/acl_hci_link_interface.h" @@ -59,7 +60,6 @@ #include "stack/include/sco_hci_link_interface.h" #include "stack/include/sec_hci_link_interface.h" #include "stack/include/smp_api.h" -#include "stack/include/stack_metrics_logging.h" #include "types/hci_role.h" #include "types/raw_address.h" @@ -110,7 +110,7 @@ static void btu_hcif_log_event_metrics(uint8_t evt_code, const uint8_t* p_event) uint32_t cmd = android::bluetooth::hci::CMD_UNKNOWN; uint16_t status = android::bluetooth::hci::STATUS_UNKNOWN; uint16_t reason = android::bluetooth::hci::STATUS_UNKNOWN; - uint16_t handle = bluetooth::common::kUnknownConnectionHandle; + uint16_t handle = bluetooth::os::kUnknownConnectionHandle; int64_t value = 0; RawAddress bda = RawAddress::kEmpty; @@ -125,25 +125,29 @@ static void btu_hcif_log_event_metrics(uint8_t evt_code, const uint8_t* p_event) case HCI_KEYPRESS_NOTIFY_EVT: case HCI_REMOTE_OOB_DATA_REQUEST_EVT: STREAM_TO_BDADDR(bda, p_event); - log_classic_pairing_event(bda, handle, cmd, evt_code, status, reason, value); + bluetooth::shim::LogMetricClassicPairingEvent(bda, handle, cmd, evt_code, status, reason, + value); break; case HCI_SIMPLE_PAIRING_COMPLETE_EVT: STREAM_TO_UINT8(status, p_event); STREAM_TO_BDADDR(bda, p_event); - log_classic_pairing_event(bda, handle, cmd, evt_code, status, reason, value); + bluetooth::shim::LogMetricClassicPairingEvent(bda, handle, cmd, evt_code, status, reason, + value); break; case HCI_AUTHENTICATION_COMP_EVT: STREAM_TO_UINT8(status, p_event); STREAM_TO_UINT16(handle, p_event); handle = HCID_GET_HANDLE(handle); - log_classic_pairing_event(bda, handle, cmd, evt_code, status, reason, value); + bluetooth::shim::LogMetricClassicPairingEvent(bda, handle, cmd, evt_code, status, reason, + value); break; case HCI_ENCRYPTION_CHANGE_EVT: { uint8_t encryption_enabled; STREAM_TO_UINT8(status, p_event); STREAM_TO_UINT16(handle, p_event); STREAM_TO_UINT8(encryption_enabled, p_event); - log_classic_pairing_event(bda, handle, cmd, evt_code, status, reason, encryption_enabled); + bluetooth::shim::LogMetricClassicPairingEvent(bda, handle, cmd, evt_code, status, reason, + encryption_enabled); break; } case HCI_ENCRYPTION_CHANGE_EVT_V2: { @@ -153,7 +157,8 @@ static void btu_hcif_log_event_metrics(uint8_t evt_code, const uint8_t* p_event) STREAM_TO_UINT16(handle, p_event); STREAM_TO_UINT8(encryption_enabled, p_event); STREAM_TO_UINT8(key_size, p_event); - log_classic_pairing_event(bda, handle, cmd, evt_code, status, reason, encryption_enabled); + bluetooth::shim::LogMetricClassicPairingEvent(bda, handle, cmd, evt_code, status, reason, + encryption_enabled); break; } case HCI_ESCO_CONNECTION_COMP_EVT: { @@ -163,18 +168,19 @@ static void btu_hcif_log_event_metrics(uint8_t evt_code, const uint8_t* p_event) STREAM_TO_BDADDR(bda, p_event); STREAM_TO_UINT8(link_type, p_event); handle = HCID_GET_HANDLE(handle); - log_link_layer_connection_event(&bda, handle, android::bluetooth::DIRECTION_UNKNOWN, - link_type, cmd, evt_code, - android::bluetooth::hci::BLE_EVT_UNKNOWN, status, reason); + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + &bda, handle, android::bluetooth::DIRECTION_UNKNOWN, link_type, cmd, evt_code, + android::bluetooth::hci::BLE_EVT_UNKNOWN, status, reason); break; } case HCI_ESCO_CONNECTION_CHANGED_EVT: { STREAM_TO_UINT8(status, p_event); STREAM_TO_UINT16(handle, p_event); handle = HCID_GET_HANDLE(handle); - log_link_layer_connection_event(nullptr, handle, android::bluetooth::DIRECTION_UNKNOWN, - android::bluetooth::LINK_TYPE_UNKNOWN, cmd, evt_code, - android::bluetooth::hci::BLE_EVT_UNKNOWN, status, reason); + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + nullptr, handle, android::bluetooth::DIRECTION_UNKNOWN, + android::bluetooth::LINK_TYPE_UNKNOWN, cmd, evt_code, + android::bluetooth::hci::BLE_EVT_UNKNOWN, status, reason); break; } // Ignore these events @@ -368,32 +374,33 @@ static void btu_hcif_log_command_metrics(uint16_t opcode, const uint8_t* p_cmd, case HCI_CREATE_CONNECTION: case HCI_CREATE_CONNECTION_CANCEL: STREAM_TO_BDADDR(bd_addr, p_cmd); - log_link_layer_connection_event( - &bd_addr, bluetooth::common::kUnknownConnectionHandle, + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + &bd_addr, bluetooth::os::kUnknownConnectionHandle, android::bluetooth::DIRECTION_OUTGOING, android::bluetooth::LINK_TYPE_ACL, opcode, hci_event, kUnknownBleEvt, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN); break; case HCI_DISCONNECT: STREAM_TO_UINT16(handle, p_cmd); STREAM_TO_UINT8(reason, p_cmd); - log_link_layer_connection_event(nullptr, handle, android::bluetooth::DIRECTION_UNKNOWN, - android::bluetooth::LINK_TYPE_UNKNOWN, opcode, hci_event, - kUnknownBleEvt, cmd_status, reason); + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + nullptr, handle, android::bluetooth::DIRECTION_UNKNOWN, + android::bluetooth::LINK_TYPE_UNKNOWN, opcode, hci_event, kUnknownBleEvt, cmd_status, + reason); break; case HCI_SETUP_ESCO_CONNECTION: case HCI_ENH_SETUP_ESCO_CONNECTION: STREAM_TO_UINT16(handle, p_cmd); - log_link_layer_connection_event(nullptr, handle, android::bluetooth::DIRECTION_OUTGOING, - android::bluetooth::LINK_TYPE_UNKNOWN, opcode, hci_event, - kUnknownBleEvt, cmd_status, - android::bluetooth::hci::STATUS_UNKNOWN); + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + nullptr, handle, android::bluetooth::DIRECTION_OUTGOING, + android::bluetooth::LINK_TYPE_UNKNOWN, opcode, hci_event, kUnknownBleEvt, cmd_status, + android::bluetooth::hci::STATUS_UNKNOWN); break; case HCI_ACCEPT_CONNECTION_REQUEST: case HCI_ACCEPT_ESCO_CONNECTION: case HCI_ENH_ACCEPT_ESCO_CONNECTION: STREAM_TO_BDADDR(bd_addr, p_cmd); - log_link_layer_connection_event( - &bd_addr, bluetooth::common::kUnknownConnectionHandle, + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + &bd_addr, bluetooth::os::kUnknownConnectionHandle, android::bluetooth::DIRECTION_INCOMING, android::bluetooth::LINK_TYPE_UNKNOWN, opcode, hci_event, kUnknownBleEvt, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN); break; @@ -401,10 +408,10 @@ static void btu_hcif_log_command_metrics(uint16_t opcode, const uint8_t* p_cmd, case HCI_REJECT_ESCO_CONNECTION: STREAM_TO_BDADDR(bd_addr, p_cmd); STREAM_TO_UINT8(reason, p_cmd); - log_link_layer_connection_event(&bd_addr, bluetooth::common::kUnknownConnectionHandle, - android::bluetooth::DIRECTION_INCOMING, - android::bluetooth::LINK_TYPE_UNKNOWN, opcode, hci_event, - kUnknownBleEvt, cmd_status, reason); + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + &bd_addr, bluetooth::os::kUnknownConnectionHandle, + android::bluetooth::DIRECTION_INCOMING, android::bluetooth::LINK_TYPE_UNKNOWN, opcode, + hci_event, kUnknownBleEvt, cmd_status, reason); break; // BLE Commands @@ -431,8 +438,8 @@ static void btu_hcif_log_command_metrics(uint16_t opcode, const uint8_t* p_cmd, // Selectively log to avoid log spam due to acceptlist connections: // - When doing non-acceptlist connection // - When there is an error in command status - log_link_layer_connection_event( - bd_addr_p, bluetooth::common::kUnknownConnectionHandle, + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + bd_addr_p, bluetooth::os::kUnknownConnectionHandle, android::bluetooth::DIRECTION_OUTGOING, android::bluetooth::LINK_TYPE_ACL, opcode, hci_event, kUnknownBleEvt, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN); } @@ -456,8 +463,8 @@ static void btu_hcif_log_command_metrics(uint16_t opcode, const uint8_t* p_cmd, // Selectively log to avoid log spam due to acceptlist connections: // - When doing non-acceptlist connection // - When there is an error in command status - log_link_layer_connection_event( - bd_addr_p, bluetooth::common::kUnknownConnectionHandle, + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + bd_addr_p, bluetooth::os::kUnknownConnectionHandle, android::bluetooth::DIRECTION_OUTGOING, android::bluetooth::LINK_TYPE_ACL, opcode, hci_event, kUnknownBleEvt, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN); } @@ -466,54 +473,56 @@ static void btu_hcif_log_command_metrics(uint16_t opcode, const uint8_t* p_cmd, case HCI_BLE_CREATE_CONN_CANCEL: if (cmd_status != HCI_SUCCESS && !is_cmd_status) { // Only log errors to prevent log spam due to acceptlist connections - log_link_layer_connection_event( - nullptr, bluetooth::common::kUnknownConnectionHandle, + bluetooth::shim::LogMetricLinkLayerConnectionEvent( + nullptr, bluetooth::os::kUnknownConnectionHandle, android::bluetooth::DIRECTION_OUTGOING, android::bluetooth::LINK_TYPE_ACL, opcode, hci_event, kUnknownBleEvt, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN); } break; case HCI_READ_LOCAL_OOB_DATA: case HCI_READ_LOCAL_OOB_EXTENDED_DATA: - log_classic_pairing_event(RawAddress::kEmpty, bluetooth::common::kUnknownConnectionHandle, - opcode, hci_event, cmd_status, - android::bluetooth::hci::STATUS_UNKNOWN, 0); + bluetooth::shim::LogMetricClassicPairingEvent( + RawAddress::kEmpty, bluetooth::os::kUnknownConnectionHandle, opcode, hci_event, + cmd_status, android::bluetooth::hci::STATUS_UNKNOWN, 0); break; case HCI_WRITE_SIMPLE_PAIRING_MODE: { uint8_t simple_pairing_mode; STREAM_TO_UINT8(simple_pairing_mode, p_cmd); - log_classic_pairing_event(RawAddress::kEmpty, bluetooth::common::kUnknownConnectionHandle, - opcode, hci_event, cmd_status, - android::bluetooth::hci::STATUS_UNKNOWN, simple_pairing_mode); + bluetooth::shim::LogMetricClassicPairingEvent( + RawAddress::kEmpty, bluetooth::os::kUnknownConnectionHandle, opcode, hci_event, + cmd_status, android::bluetooth::hci::STATUS_UNKNOWN, simple_pairing_mode); break; } case HCI_WRITE_SECURE_CONNS_SUPPORT: { uint8_t secure_conn_host_support; STREAM_TO_UINT8(secure_conn_host_support, p_cmd); - log_classic_pairing_event(RawAddress::kEmpty, bluetooth::common::kUnknownConnectionHandle, - opcode, hci_event, cmd_status, - android::bluetooth::hci::STATUS_UNKNOWN, secure_conn_host_support); + bluetooth::shim::LogMetricClassicPairingEvent( + RawAddress::kEmpty, bluetooth::os::kUnknownConnectionHandle, opcode, hci_event, + cmd_status, android::bluetooth::hci::STATUS_UNKNOWN, secure_conn_host_support); break; } case HCI_AUTHENTICATION_REQUESTED: STREAM_TO_UINT16(handle, p_cmd); - log_classic_pairing_event(RawAddress::kEmpty, handle, opcode, hci_event, cmd_status, - android::bluetooth::hci::STATUS_UNKNOWN, 0); + bluetooth::shim::LogMetricClassicPairingEvent(RawAddress::kEmpty, handle, opcode, hci_event, + cmd_status, + android::bluetooth::hci::STATUS_UNKNOWN, 0); break; case HCI_SET_CONN_ENCRYPTION: { STREAM_TO_UINT16(handle, p_cmd); uint8_t encryption_enable; STREAM_TO_UINT8(encryption_enable, p_cmd); - log_classic_pairing_event(RawAddress::kEmpty, handle, opcode, hci_event, cmd_status, - android::bluetooth::hci::STATUS_UNKNOWN, encryption_enable); + bluetooth::shim::LogMetricClassicPairingEvent( + RawAddress::kEmpty, handle, opcode, hci_event, cmd_status, + android::bluetooth::hci::STATUS_UNKNOWN, encryption_enable); break; } case HCI_DELETE_STORED_LINK_KEY: { uint8_t delete_all_flag; STREAM_TO_BDADDR(bd_addr, p_cmd); STREAM_TO_UINT8(delete_all_flag, p_cmd); - log_classic_pairing_event(bd_addr, bluetooth::common::kUnknownConnectionHandle, opcode, - hci_event, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN, - delete_all_flag); + bluetooth::shim::LogMetricClassicPairingEvent( + bd_addr, bluetooth::os::kUnknownConnectionHandle, opcode, hci_event, cmd_status, + android::bluetooth::hci::STATUS_UNKNOWN, delete_all_flag); break; } case HCI_RMT_NAME_REQUEST: @@ -528,14 +537,16 @@ static void btu_hcif_log_command_metrics(uint16_t opcode, const uint8_t* p_cmd, case HCI_REM_OOB_DATA_REQ_REPLY: case HCI_REM_OOB_DATA_REQ_NEG_REPLY: STREAM_TO_BDADDR(bd_addr, p_cmd); - log_classic_pairing_event(bd_addr, bluetooth::common::kUnknownConnectionHandle, opcode, - hci_event, cmd_status, android::bluetooth::hci::STATUS_UNKNOWN, 0); + bluetooth::shim::LogMetricClassicPairingEvent( + bd_addr, bluetooth::os::kUnknownConnectionHandle, opcode, hci_event, cmd_status, + android::bluetooth::hci::STATUS_UNKNOWN, 0); break; case HCI_IO_CAP_REQ_NEG_REPLY: STREAM_TO_BDADDR(bd_addr, p_cmd); STREAM_TO_UINT8(reason, p_cmd); - log_classic_pairing_event(bd_addr, bluetooth::common::kUnknownConnectionHandle, opcode, - hci_event, cmd_status, reason, 0); + bluetooth::shim::LogMetricClassicPairingEvent(bd_addr, + bluetooth::os::kUnknownConnectionHandle, opcode, + hci_event, cmd_status, reason, 0); break; } } @@ -599,8 +610,9 @@ static void btu_hcif_log_command_complete_metrics(uint16_t opcode, const uint8_t case HCI_WRITE_SIMPLE_PAIRING_MODE: case HCI_WRITE_SECURE_CONNS_SUPPORT: STREAM_TO_UINT8(status, p_return_params); - log_classic_pairing_event(RawAddress::kEmpty, bluetooth::common::kUnknownConnectionHandle, - opcode, hci_event, status, reason, 0); + bluetooth::shim::LogMetricClassicPairingEvent(RawAddress::kEmpty, + bluetooth::os::kUnknownConnectionHandle, opcode, + hci_event, status, reason, 0); break; case HCI_READ_ENCR_KEY_SIZE: { uint16_t handle; @@ -608,8 +620,8 @@ static void btu_hcif_log_command_complete_metrics(uint16_t opcode, const uint8_t STREAM_TO_UINT8(status, p_return_params); STREAM_TO_UINT16(handle, p_return_params); STREAM_TO_UINT8(key_size, p_return_params); - log_classic_pairing_event(RawAddress::kEmpty, handle, opcode, hci_event, status, reason, - key_size); + bluetooth::shim::LogMetricClassicPairingEvent(RawAddress::kEmpty, handle, opcode, hci_event, + status, reason, key_size); break; } case HCI_LINK_KEY_REQUEST_REPLY: @@ -624,8 +636,9 @@ static void btu_hcif_log_command_complete_metrics(uint16_t opcode, const uint8_t case HCI_REM_OOB_DATA_REQ_NEG_REPLY: STREAM_TO_UINT8(status, p_return_params); STREAM_TO_BDADDR(bd_addr, p_return_params); - log_classic_pairing_event(bd_addr, bluetooth::common::kUnknownConnectionHandle, opcode, - hci_event, status, reason, 0); + bluetooth::shim::LogMetricClassicPairingEvent(bd_addr, + bluetooth::os::kUnknownConnectionHandle, opcode, + hci_event, status, reason, 0); break; } } diff --git a/system/stack/eatt/eatt_impl.h b/system/stack/eatt/eatt_impl.h index 0d27726af4..b602636f0d 100644 --- a/system/stack/eatt/eatt_impl.h +++ b/system/stack/eatt/eatt_impl.h @@ -723,11 +723,7 @@ struct eatt_impl { tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(channel->bda_, BT_TRANSPORT_LE); log::warn("disconnecting channel {:#x} for {}", channel->cid_, channel->bda_); - if (com::android::bluetooth::flags::gatt_disconnect_fix()) { - EattExtension::GetInstance()->Disconnect(channel->bda_, channel->cid_); - } else { - gatt_disconnect(p_tcb); - } + EattExtension::GetInstance()->Disconnect(channel->bda_, channel->cid_); } void start_indication_confirm_timer(const RawAddress& bd_addr, uint16_t cid) { diff --git a/system/stack/fuzzers/l2cap_fuzzer.cc b/system/stack/fuzzers/l2cap_fuzzer.cc index 6cb4d5170f..69243a67c4 100644 --- a/system/stack/fuzzers/l2cap_fuzzer.cc +++ b/system/stack/fuzzers/l2cap_fuzzer.cc @@ -121,26 +121,30 @@ public: GetInterfaceToProfiles()->profileSpecific_HACK->GetHearingAidDeviceCount = []() { return 1; }; - ON_CALL(controller_, GetLeSuggestedDefaultDataLength).WillByDefault(Return(512)); + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); + ON_CALL(*bluetooth::hci::testing::mock_controller_, GetLeSuggestedDefaultDataLength) + .WillByDefault(Return(512)); bluetooth::hci::LeBufferSize iso_size; iso_size.le_data_packet_length_ = 512; iso_size.total_num_le_packets_ = 6; - ON_CALL(controller_, GetControllerIsoBufferSize).WillByDefault(Return(iso_size)); + ON_CALL(*bluetooth::hci::testing::mock_controller_, GetControllerIsoBufferSize) + .WillByDefault(Return(iso_size)); bluetooth::hci::LeBufferSize le_size; le_size.le_data_packet_length_ = 512; le_size.total_num_le_packets_ = 6; - ON_CALL(controller_, GetLeBufferSize).WillByDefault(Return(le_size)); - ON_CALL(controller_, SupportsBle).WillByDefault(Return(true)); - ON_CALL(controller_, GetAclPacketLength).WillByDefault(Return(512)); - bluetooth::hci::testing::mock_controller_ = &controller_; + ON_CALL(*bluetooth::hci::testing::mock_controller_, GetLeBufferSize) + .WillByDefault(Return(le_size)); + ON_CALL(*bluetooth::hci::testing::mock_controller_, SupportsBle).WillByDefault(Return(true)); + ON_CALL(*bluetooth::hci::testing::mock_controller_, GetAclPacketLength) + .WillByDefault(Return(512)); } ~FakeBtStack() { test::mock::stack_acl::acl_send_data_packet_br_edr = {}; test::mock::stack_acl::acl_send_data_packet_ble = {}; - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); } - bluetooth::hci::testing::MockControllerInterface controller_; }; class Fakes { diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc index 1b60132b00..bb5641d97d 100644 --- a/system/stack/gatt/gatt_api.cc +++ b/system/stack/gatt/gatt_api.cc @@ -34,6 +34,7 @@ #include "internal_include/bt_target.h" #include "internal_include/stack_config.h" #include "main/shim/helpers.h" +#include "main/shim/metrics_api.h" #include "os/system_properties.h" #include "osi/include/allocator.h" #include "stack/arbiter/acl_arbiter.h" @@ -48,7 +49,6 @@ #include "stack/include/l2cap_interface.h" #include "stack/include/l2cdefs.h" #include "stack/include/sdp_api.h" -#include "stack/include/stack_metrics_logging.h" #include "types/bluetooth/uuid.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -75,8 +75,7 @@ static tGATT_HDL_LIST_ELEM& gatt_add_an_item_to_list(uint16_t s_handle) { return *rit; } -static tGATT_IF GATT_Register_Dynamic(const Uuid& app_uuid128, const std::string& name, - tGATT_CBACK* p_cb_info, bool eatt_support); +static tGATT_IF GATT_FindNextFreeClRcbId(); /***************************************************************************** * @@ -1229,63 +1228,6 @@ void GATT_SetIdleTimeout(const RawAddress& bd_addr, uint16_t idle_tout, tBT_TRAN ******************************************************************************/ tGATT_IF GATT_Register(const Uuid& app_uuid128, const std::string& name, tGATT_CBACK* p_cb_info, bool eatt_support) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - return GATT_Register_Dynamic(app_uuid128, name, p_cb_info, eatt_support); - } - tGATT_REG* p_reg; - uint8_t i_gatt_if = 0; - tGATT_IF gatt_if = 0; - - for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++) { - if (p_reg->in_use && p_reg->app_uuid128 == app_uuid128) { - log::error("Application already registered, uuid={}", app_uuid128.ToString()); - return 0; - } - } - - if (stack_config_get_interface()->get_pts_use_eatt_for_all_services()) { - log::info("PTS: Force to use EATT for servers"); - eatt_support = true; - } - - for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++) { - if (!p_reg->in_use) { - *p_reg = {}; - i_gatt_if++; /* one based number */ - p_reg->app_uuid128 = app_uuid128; - gatt_if = p_reg->gatt_if = (tGATT_IF)i_gatt_if; - p_reg->app_cb = *p_cb_info; - p_reg->in_use = true; - p_reg->eatt_support = eatt_support; - p_reg->name = name; - log::info("Allocated name:{} uuid:{} gatt_if:{} eatt_support:{}", name, - app_uuid128.ToString(), gatt_if, eatt_support); - return gatt_if; - } - } - - log::error("Unable to register GATT client, MAX client reached: {}", GATT_MAX_APPS); - return 0; -} - -static tGATT_IF GATT_FindNextFreeClRcbId() { - tGATT_IF gatt_if = gatt_cb.last_gatt_if; - for (int i = 0; i < GATT_IF_MAX; i++) { - if (++gatt_if > GATT_IF_MAX) { - gatt_if = static_cast<tGATT_IF>(1); - } - if (!gatt_cb.cl_rcb_map.contains(gatt_if)) { - gatt_cb.last_gatt_if = gatt_if; - return gatt_if; - } - } - log::error("Unable to register GATT client, MAX client reached: {}", gatt_cb.cl_rcb_map.size()); - - return GATT_IF_INVALID; -} - -static tGATT_IF GATT_Register_Dynamic(const Uuid& app_uuid128, const std::string& name, - tGATT_CBACK* p_cb_info, bool eatt_support) { for (auto& [gatt_if, p_reg] : gatt_cb.cl_rcb_map) { if (p_reg->app_uuid128 == app_uuid128) { log::error("Application already registered, uuid={}", app_uuid128.ToString()); @@ -1322,6 +1264,22 @@ static tGATT_IF GATT_Register_Dynamic(const Uuid& app_uuid128, const std::string return gatt_if; } +static tGATT_IF GATT_FindNextFreeClRcbId() { + tGATT_IF gatt_if = gatt_cb.last_gatt_if; + for (int i = 0; i < GATT_IF_MAX; i++) { + if (++gatt_if > GATT_IF_MAX) { + gatt_if = static_cast<tGATT_IF>(1); + } + if (!gatt_cb.cl_rcb_map.contains(gatt_if)) { + gatt_cb.last_gatt_if = gatt_if; + return gatt_if; + } + } + log::error("Unable to register GATT client, MAX client reached: {}", gatt_cb.cl_rcb_map.size()); + + return GATT_IF_INVALID; +} + /******************************************************************************* * * Function GATT_Deregister @@ -1385,11 +1343,7 @@ void GATT_Deregister(tGATT_IF gatt_if) { connection_manager::on_app_deregistered(gatt_if); - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - gatt_cb.cl_rcb_map.erase(gatt_if); - } else { - *p_reg = {}; - } + gatt_cb.cl_rcb_map.erase(gatt_if); } /******************************************************************************* @@ -1476,7 +1430,8 @@ bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, tBLE_ADDR_TYPE ad return true; } - log_le_connection_lifecycle(ToGdAddress(bd_addr), true /* is_connect */, is_direct); + bluetooth::shim::LogMetricLeConnectionLifecycle(ToGdAddress(bd_addr), true /* is_connect */, + is_direct); bool ret = false; if (is_direct) { @@ -1618,8 +1573,8 @@ tGATT_STATUS GATT_Disconnect(tCONN_ID conn_id) { return GATT_ILLEGAL_PARAMETER; } - log_le_connection_lifecycle(ToGdAddress(p_tcb->peer_bda), true /* is_connect */, - false /* is_direct */); + bluetooth::shim::LogMetricLeConnectionLifecycle(ToGdAddress(p_tcb->peer_bda), + true /* is_connect */, false /* is_direct */); tGATT_IF gatt_if = gatt_get_gatt_if(conn_id); gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true); diff --git a/system/stack/gatt/gatt_auth.cc b/system/stack/gatt/gatt_auth.cc index 7c4b935389..34dcb4886b 100644 --- a/system/stack/gatt/gatt_auth.cc +++ b/system/stack/gatt/gatt_auth.cc @@ -23,7 +23,6 @@ ******************************************************************************/ #include <bluetooth/log.h> -#include <com_android_bluetooth_flags.h> #include <string.h> #include "gatt_api.h" @@ -216,17 +215,9 @@ void gatt_notify_enc_cmpl(const RawAddress& bd_addr) { return; } - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_rcb] : gatt_cb.cl_rcb_map) { - if (p_rcb->app_cb.p_enc_cmpl_cb) { - (*p_rcb->app_cb.p_enc_cmpl_cb)(p_rcb->gatt_if, bd_addr); - } - } - } else { - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) { - (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if, bd_addr); - } + for (auto& [i, p_rcb] : gatt_cb.cl_rcb_map) { + if (p_rcb->app_cb.p_enc_cmpl_cb) { + (*p_rcb->app_cb.p_enc_cmpl_cb)(p_rcb->gatt_if, bd_addr); } } diff --git a/system/stack/gatt/gatt_cl.cc b/system/stack/gatt/gatt_cl.cc index 9a241813ae..8496d425a1 100644 --- a/system/stack/gatt/gatt_cl.cc +++ b/system/stack/gatt/gatt_cl.cc @@ -25,7 +25,6 @@ #define LOG_TAG "bluetooth" #include <bluetooth/log.h> -#include <com_android_bluetooth_flags.h> #include <string.h> #include "gatt_int.h" @@ -708,17 +707,9 @@ static void gatt_process_notification(tGATT_TCB& tcb, uint16_t cid, uint8_t op_c // notification/indication // Note: need to do the indication count and start timer first then do // callback - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { - tcb.ind_count++; - } - } - } else { - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { - tcb.ind_count++; - } + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { + tcb.ind_count++; } } @@ -738,19 +729,10 @@ static void gatt_process_notification(tGATT_TCB& tcb, uint16_t cid, uint8_t op_c gatt_cl_complete.att_value = value; gatt_cl_complete.cid = cid; - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { - conn_id = gatt_create_conn_id(tcb.tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); - } - } - } else { - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { - conn_id = gatt_create_conn_id(tcb.tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); - } + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { + conn_id = gatt_create_conn_id(tcb.tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); } } @@ -788,19 +770,10 @@ static void gatt_process_notification(tGATT_TCB& tcb, uint16_t cid, uint8_t op_c gatt_cl_complete.att_value = value; gatt_cl_complete.cid = cid; - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { - conn_id = gatt_create_conn_id(tcb.tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); - } - } - } else { - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { - conn_id = gatt_create_conn_id(tcb.tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); - } + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { + conn_id = gatt_create_conn_id(tcb.tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status, &gatt_cl_complete); } } } diff --git a/system/stack/gatt/gatt_main.cc b/system/stack/gatt/gatt_main.cc index 56d268422c..5228369a26 100644 --- a/system/stack/gatt/gatt_main.cc +++ b/system/stack/gatt/gatt_main.cc @@ -282,7 +282,7 @@ bool gatt_disconnect(tGATT_TCB* p_tcb) { return true; } - if (com::android::bluetooth::flags::gatt_disconnect_fix() && p_tcb->eatt) { + if (p_tcb->eatt) { /* ATT is fixed channel and it is expected to drop ACL. * Make sure all EATT channels are disconnected before doing that. */ @@ -624,21 +624,10 @@ static void gatt_channel_congestion(tGATT_TCB* p_tcb, bool congested) { gatt_cl_send_next_cmd_inq(*p_tcb); } /* notifying all applications for the connection up event */ - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (p_reg->in_use && p_reg->app_cb.p_congestion_cb) { - conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_congestion_cb)(conn_id, congested); - } - } - } else { - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (p_reg->in_use) { - if (p_reg->app_cb.p_congestion_cb) { - conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_congestion_cb)(conn_id, congested); - } - } + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_congestion_cb) { + conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_congestion_cb)(conn_id, congested); } } } @@ -658,20 +647,10 @@ void gatt_notify_phy_updated(tHCI_STATUS status, uint16_t handle, uint8_t tx_phy // TODO: Clean up this status conversion. tGATT_STATUS gatt_status = static_cast<tGATT_STATUS>(status); - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (p_reg->in_use && p_reg->app_cb.p_phy_update_cb) { - tCONN_ID conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_phy_update_cb)(p_reg->gatt_if, conn_id, tx_phy, rx_phy, gatt_status); - } - } - } else { - for (int i = 0; i < GATT_MAX_APPS; i++) { - tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; - if (p_reg->in_use && p_reg->app_cb.p_phy_update_cb) { - tCONN_ID conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_phy_update_cb)(p_reg->gatt_if, conn_id, tx_phy, rx_phy, gatt_status); - } + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_phy_update_cb) { + tCONN_ID conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_phy_update_cb)(p_reg->gatt_if, conn_id, tx_phy, rx_phy, gatt_status); } } } @@ -684,22 +663,11 @@ void gatt_notify_conn_update(const RawAddress& remote, uint16_t interval, uint16 return; } - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (p_reg->in_use && p_reg->app_cb.p_conn_update_cb) { - tCONN_ID conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_conn_update_cb)(p_reg->gatt_if, conn_id, interval, latency, timeout, - static_cast<tGATT_STATUS>(status)); - } - } - } else { - for (int i = 0; i < GATT_MAX_APPS; i++) { - tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; - if (p_reg->in_use && p_reg->app_cb.p_conn_update_cb) { - tCONN_ID conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_conn_update_cb)(p_reg->gatt_if, conn_id, interval, latency, timeout, - static_cast<tGATT_STATUS>(status)); - } + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_conn_update_cb) { + tCONN_ID conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_conn_update_cb)(p_reg->gatt_if, conn_id, interval, latency, timeout, + static_cast<tGATT_STATUS>(status)); } } } @@ -717,22 +685,11 @@ void gatt_notify_subrate_change(uint16_t handle, uint16_t subrate_factor, uint16 return; } - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (p_reg->in_use && p_reg->app_cb.p_subrate_chg_cb) { - tCONN_ID conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_subrate_chg_cb)(p_reg->gatt_if, conn_id, subrate_factor, latency, - cont_num, timeout, static_cast<tGATT_STATUS>(status)); - } - } - } else { - for (int i = 0; i < GATT_MAX_APPS; i++) { - tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; - if (p_reg->in_use && p_reg->app_cb.p_subrate_chg_cb) { - tCONN_ID conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_subrate_chg_cb)(p_reg->gatt_if, conn_id, subrate_factor, latency, - cont_num, timeout, static_cast<tGATT_STATUS>(status)); - } + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_subrate_chg_cb) { + tCONN_ID conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_subrate_chg_cb)(p_reg->gatt_if, conn_id, subrate_factor, latency, cont_num, + timeout, static_cast<tGATT_STATUS>(status)); } } } @@ -976,37 +933,19 @@ static void gatt_send_conn_cback(tGATT_TCB* p_tcb) { /* notifying all applications for the connection up event */ - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (!p_reg->in_use) { - continue; - } - - if (apps.find(p_reg->gatt_if) != apps.end()) { - gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true); - } - - if (p_reg->app_cb.p_conn_cb) { - conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id, kGattConnected, - GATT_CONN_OK, p_tcb->transport); - } + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (!p_reg->in_use) { + continue; } - } else { - for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { - if (!p_reg->in_use) { - continue; - } - if (apps.find(p_reg->gatt_if) != apps.end()) { - gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true); - } + if (apps.find(p_reg->gatt_if) != apps.end()) { + gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true); + } - if (p_reg->app_cb.p_conn_cb) { - conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); - (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id, kGattConnected, - GATT_CONN_OK, p_tcb->transport); - } + if (p_reg->app_cb.p_conn_cb) { + conn_id = gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id, kGattConnected, + GATT_CONN_OK, p_tcb->transport); } } diff --git a/system/stack/gatt/gatt_sr.cc b/system/stack/gatt/gatt_sr.cc index 133080c1db..f23b8b5dc9 100644 --- a/system/stack/gatt/gatt_sr.cc +++ b/system/stack/gatt/gatt_sr.cc @@ -407,27 +407,14 @@ static void gatt_process_exec_write_req(tGATT_TCB& tcb, uint16_t cid, uint8_t op trans_id = gatt_sr_enqueue_cmd(tcb, cid, op_code, 0); gatt_sr_copy_prep_cnt_to_cback_cnt(tcb); - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - auto prep_cnt_it = tcb.prep_cnt_map.begin(); - while (prep_cnt_it != tcb.prep_cnt_map.end()) { - gatt_if = prep_cnt_it->first; - conn_id = gatt_create_conn_id(tcb.tcb_idx, gatt_if); - tGATTS_DATA gatts_data; - gatts_data.exec_write = flag; - gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE_EXEC, &gatts_data); - prep_cnt_it = tcb.prep_cnt_map.erase(prep_cnt_it); - } - } else { - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - if (tcb.prep_cnt[i]) { - gatt_if = (tGATT_IF)(i + 1); - conn_id = gatt_create_conn_id(tcb.tcb_idx, gatt_if); - tGATTS_DATA gatts_data; - gatts_data.exec_write = flag; - gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE_EXEC, &gatts_data); - tcb.prep_cnt[i] = 0; - } - } + auto prep_cnt_it = tcb.prep_cnt_map.begin(); + while (prep_cnt_it != tcb.prep_cnt_map.end()) { + gatt_if = prep_cnt_it->first; + conn_id = gatt_create_conn_id(tcb.tcb_idx, gatt_if); + tGATTS_DATA gatts_data; + gatts_data.exec_write = flag; + gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE_EXEC, &gatts_data); + prep_cnt_it = tcb.prep_cnt_map.erase(prep_cnt_it); } } else { /* nothing needs to be executed , send response now */ log::warn("gatt_process_exec_write_req: no prepare write pending"); @@ -911,19 +898,10 @@ static void gatts_process_mtu_req(tGATT_TCB& tcb, uint16_t cid, uint16_t len, ui gatts_data.mtu = tcb.payload_size; /* Notify all registered application with new MTU size. Use a transaction ID */ /* of 0, as no response is allowed from applications */ - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (p_reg->in_use) { - tCONN_ID conn_id = gatt_create_conn_id(tcb.tcb_idx, p_reg->gatt_if); - gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU, &gatts_data); - } - } - } else { - for (int i = 0; i < GATT_MAX_APPS; i++) { - if (gatt_cb.cl_rcb[i].in_use) { - tCONN_ID conn_id = gatt_create_conn_id(tcb.tcb_idx, gatt_cb.cl_rcb[i].gatt_if); - gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU, &gatts_data); - } + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use) { + tCONN_ID conn_id = gatt_create_conn_id(tcb.tcb_idx, p_reg->gatt_if); + gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU, &gatts_data); } } } diff --git a/system/stack/gatt/gatt_utils.cc b/system/stack/gatt/gatt_utils.cc index f401be9285..28590330c5 100644 --- a/system/stack/gatt/gatt_utils.cc +++ b/system/stack/gatt/gatt_utils.cc @@ -24,7 +24,6 @@ #define LOG_TAG "gatt_utils" #include <bluetooth/log.h> -#include <com_android_bluetooth_flags.h> #include <cstdint> #include <deque> @@ -1043,21 +1042,12 @@ tGATT_REG* gatt_get_regcb(tGATT_IF gatt_if) { uint8_t ii = (uint8_t)gatt_if; tGATT_REG* p_reg = NULL; - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - auto it = gatt_cb.cl_rcb_map.find(gatt_if); - if (it == gatt_cb.cl_rcb_map.end()) { - log::warn("unknown gatt_if = {}", ii); - return NULL; - } - p_reg = it->second.get(); - } else { - // Index for cl_rcb is always 1 less than gatt_if. - if (ii < 1 || ii > GATT_MAX_APPS) { - log::warn("gatt_if out of range = {}", ii); - return NULL; - } - p_reg = &gatt_cb.cl_rcb[ii - 1]; + auto it = gatt_cb.cl_rcb_map.find(gatt_if); + if (it == gatt_cb.cl_rcb_map.end()) { + log::warn("unknown gatt_if = {}", ii); + return NULL; } + p_reg = it->second.get(); if (!p_reg->in_use) { log::warn("gatt_if found but not in use."); @@ -1332,16 +1322,8 @@ tGATT_TCB* gatt_find_tcb_by_cid(uint16_t lcid) { } void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB& tcb) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, cnt] : tcb.prep_cnt_map) { - tcb.sr_cmd.cback_cnt_map[i] = 1; - } - } else { - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - if (tcb.prep_cnt[i]) { - tcb.sr_cmd.cback_cnt[i] = 1; - } - } + for (auto& [i, cnt] : tcb.prep_cnt_map) { + tcb.sr_cmd.cback_cnt_map[i] = 1; } } @@ -1385,17 +1367,7 @@ bool gatt_sr_is_cback_cnt_zero(tGATT_TCB& tcb, uint16_t cid) { sr_cmd_p = &channel->server_outstanding_cmd_; } - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - return sr_cmd_p->cback_cnt_map.empty(); - } - - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - if (sr_cmd_p->cback_cnt[i] != 0) { - return false; - } - } - - return true; + return sr_cmd_p->cback_cnt_map.empty(); } /******************************************************************************* @@ -1407,18 +1379,7 @@ bool gatt_sr_is_cback_cnt_zero(tGATT_TCB& tcb, uint16_t cid) { * Returns True no prepare write request * ******************************************************************************/ -bool gatt_sr_is_prep_cnt_zero(tGATT_TCB& tcb) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - return tcb.prep_cnt_map.empty(); - } else { - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - if (tcb.prep_cnt[i]) { - return false; - } - } - return true; - } -} +bool gatt_sr_is_prep_cnt_zero(tGATT_TCB& tcb) { return tcb.prep_cnt_map.empty(); } /******************************************************************************* * @@ -1430,31 +1391,15 @@ bool gatt_sr_is_prep_cnt_zero(tGATT_TCB& tcb) { * ******************************************************************************/ void gatt_sr_reset_cback_cnt(tGATT_TCB& tcb, uint16_t cid) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - if (cid == tcb.att_lcid) { - tcb.sr_cmd.cback_cnt_map.clear(); - } else { - EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); - if (channel == nullptr) { - log::warn("{}, cid 0x{:02x} already disconnected", tcb.peer_bda, cid); - return; - } - channel->server_outstanding_cmd_.cback_cnt_map.clear(); - } + if (cid == tcb.att_lcid) { + tcb.sr_cmd.cback_cnt_map.clear(); } else { - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - if (cid == tcb.att_lcid) { - tcb.sr_cmd.cback_cnt[i] = 0; - } else { - EattChannel* channel = - EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); - if (channel == nullptr) { - log::warn("{}, cid 0x{:02x} already disconnected", tcb.peer_bda, cid); - return; - } - channel->server_outstanding_cmd_.cback_cnt[i] = 0; - } + EattChannel* channel = EattExtension::GetInstance()->FindEattChannelByCid(tcb.peer_bda, cid); + if (channel == nullptr) { + log::warn("{}, cid 0x{:02x} already disconnected", tcb.peer_bda, cid); + return; } + channel->server_outstanding_cmd_.cback_cnt_map.clear(); } } @@ -1540,25 +1485,13 @@ void gatt_sr_update_cback_cnt(tGATT_TCB& tcb, uint16_t cid, tGATT_IF gatt_if, bo gatt_sr_reset_cback_cnt(tcb, cid); } - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - if (is_inc) { - sr_cmd_p->cback_cnt_map[gatt_if]++; - } else { - auto cback_cnt_it = sr_cmd_p->cback_cnt_map.find(gatt_if); - if (cback_cnt_it != sr_cmd_p->cback_cnt_map.end()) { - if ((--cback_cnt_it->second) <= 0) { - sr_cmd_p->cback_cnt_map.erase(cback_cnt_it); - } - } - } + if (is_inc) { + sr_cmd_p->cback_cnt_map[gatt_if]++; } else { - uint8_t idx = ((uint8_t)gatt_if) - 1; - - if (is_inc) { - sr_cmd_p->cback_cnt[idx]++; - } else { - if (sr_cmd_p->cback_cnt[idx]) { - sr_cmd_p->cback_cnt[idx]--; + auto cback_cnt_it = sr_cmd_p->cback_cnt_map.find(gatt_if); + if (cback_cnt_it != sr_cmd_p->cback_cnt_map.end()) { + if ((--cback_cnt_it->second) <= 0) { + sr_cmd_p->cback_cnt_map.erase(cback_cnt_it); } } } @@ -1582,23 +1515,13 @@ void gatt_sr_update_prep_cnt(tGATT_TCB& tcb, tGATT_IF gatt_if, bool is_inc, bool if (is_reset_first) { gatt_sr_reset_prep_cnt(tcb); } - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - if (is_inc) { - tcb.prep_cnt_map[gatt_if]++; - } else { - auto prep_cnt_i = tcb.prep_cnt_map.find(gatt_if); - if (prep_cnt_i != tcb.prep_cnt_map.end()) { - if (--prep_cnt_i->second <= 0) { - tcb.prep_cnt_map.erase(prep_cnt_i); - } - } - } + if (is_inc) { + tcb.prep_cnt_map[gatt_if]++; } else { - if (is_inc) { - tcb.prep_cnt[idx]++; - } else { - if (tcb.prep_cnt[idx]) { - tcb.prep_cnt[idx]--; + auto prep_cnt_i = tcb.prep_cnt_map.find(gatt_if); + if (prep_cnt_i != tcb.prep_cnt_map.end()) { + if (--prep_cnt_i->second <= 0) { + tcb.prep_cnt_map.erase(prep_cnt_i); } } } @@ -1806,24 +1729,12 @@ static void gatt_disconnect_complete_notify_user(const RawAddress& bda, tGATT_DI tBT_TRANSPORT transport) { tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bda, transport); - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (p_reg->in_use && p_reg->app_cb.p_conn_cb) { - tCONN_ID conn_id = - p_tcb ? gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if) : GATT_INVALID_CONN_ID; - (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, bda, conn_id, kGattDisconnected, reason, - transport); - } - } - } else { - for (uint8_t i = 0; i < GATT_MAX_APPS; i++) { - tGATT_REG* p_reg = &gatt_cb.cl_rcb[i]; - if (p_reg->in_use && p_reg->app_cb.p_conn_cb) { - tCONN_ID conn_id = - p_tcb ? gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if) : GATT_INVALID_CONN_ID; - (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, bda, conn_id, kGattDisconnected, reason, - transport); - } + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (p_reg->in_use && p_reg->app_cb.p_conn_cb) { + tCONN_ID conn_id = + p_tcb ? gatt_create_conn_id(p_tcb->tcb_idx, p_reg->gatt_if) : GATT_INVALID_CONN_ID; + (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, bda, conn_id, kGattDisconnected, reason, + transport); } } } @@ -1943,41 +1854,22 @@ uint16_t gatt_get_mtu_pref(const tGATT_REG* p_reg, const RawAddress& bda) { uint16_t gatt_get_apps_preferred_mtu(const RawAddress& bda) { uint16_t preferred_mtu = 0; - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (!p_reg->in_use) { - continue; - } - - preferred_mtu = std::max(preferred_mtu, gatt_get_mtu_pref(p_reg.get(), bda)); + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (!p_reg->in_use) { + continue; } - } else { - for (auto& reg : gatt_cb.cl_rcb) { - if (!reg.in_use) { - continue; - } - preferred_mtu = std::max(preferred_mtu, gatt_get_mtu_pref(®, bda)); - } + preferred_mtu = std::max(preferred_mtu, gatt_get_mtu_pref(p_reg.get(), bda)); } return preferred_mtu; } void gatt_remove_apps_mtu_prefs(const RawAddress& bda) { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { - if (!p_reg->in_use) { - continue; - } - p_reg.get()->mtu_prefs.erase(bda); - } - } else { - for (auto& reg : gatt_cb.cl_rcb) { - if (!reg.in_use) { - continue; - } - reg.mtu_prefs.erase(bda); + for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) { + if (!p_reg->in_use) { + continue; } + p_reg.get()->mtu_prefs.erase(bda); } } diff --git a/system/stack/hid/hidd_api.cc b/system/stack/hid/hidd_api.cc index 169868bbfc..58d9bdc07a 100644 --- a/system/stack/hid/hidd_api.cc +++ b/system/stack/hid/hidd_api.cc @@ -38,13 +38,13 @@ #include "hidd_int.h" #include "hiddefs.h" #include "internal_include/bt_target.h" +#include "main/shim/metrics_api.h" #include "osi/include/allocator.h" #include "stack/include/bt_psm_types.h" #include "stack/include/bt_types.h" #include "stack/include/bt_uuid16.h" #include "stack/include/sdp_api.h" #include "stack/include/sdpdefs.h" -#include "stack/include/stack_metrics_logging.h" #include "stack/sdp/sdp_discovery_db.h" #include "types/raw_address.h" @@ -83,12 +83,14 @@ tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback) { log::verbose(""); if (hd_cb.reg_flag) { - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_ALREADY_REGISTERED, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_ALREADY_REGISTERED, 1); return HID_ERR_ALREADY_REGISTERED; } if (host_cback == NULL) { - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_HOST_CALLBACK_NULL, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_HOST_CALLBACK_NULL, 1); return HID_ERR_INVALID_PARAM; } @@ -122,7 +124,7 @@ tHID_STATUS HID_DevDeregister(void) { log::verbose(""); if (!hd_cb.reg_flag) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NOT_REGISTERED_AT_DEREGISTER, 1); return HID_ERR_NOT_REGISTERED; } @@ -263,9 +265,10 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, if (desc_len > HIDD_APP_DESCRIPTOR_LEN) { log::error("descriptor length = {}, larger than max {}", desc_len, HIDD_APP_DESCRIPTOR_LEN); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: - HIDD_ERR_NOT_REGISTERED_DUE_TO_DESCRIPTOR_LENGTH, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum:: + HIDD_ERR_NOT_REGISTERED_DUE_TO_DESCRIPTOR_LENGTH, + 1); return HID_ERR_NOT_REGISTERED; }; @@ -273,9 +276,10 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, if (p_buf == NULL) { log::error("Buffer allocation failure for size = {}", buf_len); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum:: - HIDD_ERR_NOT_REGISTERED_DUE_TO_BUFFER_ALLOCATION, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum:: + HIDD_ERR_NOT_REGISTERED_DUE_TO_BUFFER_ALLOCATION, + 1); return HID_ERR_NOT_REGISTERED; } @@ -346,8 +350,8 @@ tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, if (!result) { log::error("failed to complete SDP record"); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NOT_REGISTERED_AT_SDP, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NOT_REGISTERED_AT_SDP, 1); return HID_ERR_NOT_REGISTERED; } @@ -376,7 +380,7 @@ tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id, uint16_ return hidd_conn_send_data(HID_CHANNEL_INTR, HID_TRANS_DATA, HID_PAR_REP_TYPE_INPUT, id, len, p_data); } - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_INVALID_PARAM_SEND_REPORT, 1); return HID_ERR_INVALID_PARAM; } @@ -444,19 +448,20 @@ tHID_STATUS HID_DevUnplugDevice(const RawAddress& addr) { ******************************************************************************/ tHID_STATUS HID_DevConnect(void) { if (!hd_cb.reg_flag) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NOT_REGISTERED_AT_CONNECT, 1); return HID_ERR_NOT_REGISTERED; } if (!hd_cb.device.in_use) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_DEVICE_NOT_IN_USE_AT_CONNECT, 1); return HID_ERR_INVALID_PARAM; } if (hd_cb.device.state != HIDD_DEV_NO_CONN) { - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_ALREADY_CONN, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_ALREADY_CONN, 1); return HID_ERR_ALREADY_CONN; } @@ -474,13 +479,13 @@ tHID_STATUS HID_DevConnect(void) { ******************************************************************************/ tHID_STATUS HID_DevDisconnect(void) { if (!hd_cb.reg_flag) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NOT_REGISTERED_AT_DISCONNECT, 1); return HID_ERR_NOT_REGISTERED; } if (!hd_cb.device.in_use) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_DEVICE_NOT_IN_USE_AT_DISCONNECT, 1); return HID_ERR_INVALID_PARAM; @@ -492,10 +497,11 @@ tHID_STATUS HID_DevDisconnect(void) { tHID_STATUS ret = hidd_conn_disconnect(); hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED; hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_DISCONNECTING, NULL); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_DISCONNECTING, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_DISCONNECTING, 1); return ret; } - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NO_CONNECTION_AT_DISCONNECT, 1); return HID_ERR_NO_CONNECTION; } @@ -565,7 +571,7 @@ tHID_STATUS HID_DevGetDevice(RawAddress* addr) { if (hd_cb.device.in_use) { *addr = hd_cb.device.addr; } else { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NOT_REGISTERED_AT_GET_DEVICE, 1); return HID_ERR_NOT_REGISTERED; } diff --git a/system/stack/hid/hidd_conn.cc b/system/stack/hid/hidd_conn.cc index 7276af8acd..5f94c1c870 100644 --- a/system/stack/hid/hidd_conn.cc +++ b/system/stack/hid/hidd_conn.cc @@ -37,13 +37,13 @@ #include "hiddefs.h" #include "internal_include/bt_target.h" #include "l2cap_types.h" +#include "main/shim/metrics_api.h" #include "osi/include/allocator.h" #include "stack/hid/hidd_int.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_psm_types.h" #include "stack/include/l2cap_interface.h" #include "stack/include/l2cdefs.h" -#include "stack/include/stack_metrics_logging.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -300,7 +300,7 @@ static void hidd_l2cif_config_cfm(uint16_t cid, uint16_t /* initiator */, tL2CAP log::warn("could not start L2CAP connection for INTR"); hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_L2CAP_NOT_STARTED_INCOMING, 1); return; } else { @@ -577,8 +577,8 @@ tHID_STATUS hidd_conn_reg(void) { HID_PSM_CONTROL, dev_reg_info, false /* enable_snoop */, nullptr, HID_DEV_MTU_SIZE, 0, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) { log::error("HID Control (device) registration failed"); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_L2CAP_FAILED_CONTROL, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_L2CAP_FAILED_CONTROL, 1); return HID_ERR_L2CAP_FAILED; } @@ -587,8 +587,8 @@ tHID_STATUS hidd_conn_reg(void) { 0, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) { stack::l2cap::get_interface().L2CA_Deregister(HID_PSM_CONTROL); log::error("HID Interrupt (device) registration failed"); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_L2CAP_FAILED_INTERRUPT, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_L2CAP_FAILED_INTERRUPT, 1); return HID_ERR_L2CAP_FAILED; } @@ -627,14 +627,15 @@ tHID_STATUS hidd_conn_initiate(void) { if (!p_dev->in_use) { log::warn("no virtual cable established"); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NOT_REGISTERED_AT_INITIATE, 1); return HID_ERR_NOT_REGISTERED; } if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) { log::warn("connection already in progress"); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_CONN_IN_PROCESS, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_CONN_IN_PROCESS, 1); return HID_ERR_CONN_IN_PROCESS; } @@ -649,8 +650,8 @@ tHID_STATUS hidd_conn_initiate(void) { HID_PSM_CONTROL, p_dev->addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) == 0) { log::warn("could not start L2CAP connection"); hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_L2CAP_FAILED_INITIATE, - 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_L2CAP_FAILED_INITIATE, 1); } else { p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL; } @@ -723,7 +724,7 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param tHID_CONN* p_hcon = &hd_cb.device.conn; if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_CONGESTED_AT_FLAG_CHECK, 1); return HID_ERR_CONGESTED; } @@ -744,13 +745,15 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param } break; default: - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_INVALID_PARAM, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_INVALID_PARAM, 1); return HID_ERR_INVALID_PARAM; } p_buf = (BT_HDR*)osi_malloc(buf_size); if (p_buf == NULL) { - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NO_RESOURCES, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NO_RESOURCES, 1); return HID_ERR_NO_RESOURCES; } @@ -792,7 +795,7 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param return HID_SUCCESS; } - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_NO_CONNECTION_AT_SEND_DATA, 1); return HID_ERR_NO_CONNECTION; } @@ -800,7 +803,7 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param log::verbose("report sent"); if (stack::l2cap::get_interface().L2CA_DataWrite(cid, p_buf) == tL2CAP_DW_RESULT::FAILED) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDD_ERR_CONGESTED_AT_DATA_WRITE, 1); return HID_ERR_CONGESTED; } diff --git a/system/stack/hid/hidh_api.cc b/system/stack/hid/hidh_api.cc index 97d811ed5b..1ab5ba2a6a 100644 --- a/system/stack/hid/hidh_api.cc +++ b/system/stack/hid/hidh_api.cc @@ -37,6 +37,7 @@ #include "hiddefs.h" #include "hidh_int.h" #include "internal_include/bt_target.h" +#include "main/shim/metrics_api.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" #include "sdp_api.h" @@ -44,7 +45,6 @@ #include "stack/include/bt_hdr.h" #include "stack/include/bt_uuid16.h" #include "stack/include/sdpdefs.h" -#include "stack/include/stack_metrics_logging.h" #include "stack/sdp/sdp_discovery_db.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" @@ -69,7 +69,8 @@ static void hidh_search_callback(const RawAddress& bd_addr, tSDP_RESULT sdp_resu tHID_STATUS HID_HostGetSDPRecord(const RawAddress& addr, tSDP_DISCOVERY_DB* p_db, uint32_t db_len, tHID_HOST_SDP_CALLBACK* sdp_cback) { if (hh_cb.sdp_busy) { - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_SDP_BUSY, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_SDP_BUSY, 1); return HID_ERR_SDP_BUSY; } @@ -87,7 +88,8 @@ tHID_STATUS HID_HostGetSDPRecord(const RawAddress& addr, tSDP_DISCOVERY_DB* p_db return HID_SUCCESS; } else { log::warn("Unable to start SDP service search request peer:{}", addr); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_NO_RESOURCES_SDP, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_NO_RESOURCES_SDP, 1); return HID_ERR_NO_RESOURCES; } } @@ -289,12 +291,13 @@ tHID_STATUS HID_HostRegister(tHID_HOST_DEV_CALLBACK* dev_cback) { tHID_STATUS st; if (hh_cb.reg_flag) { - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_ALREADY_REGISTERED, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_ALREADY_REGISTERED, 1); return HID_ERR_ALREADY_REGISTERED; } if (dev_cback == NULL) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_INVALID_PARAM_AT_HOST_REGISTER, 1); return HID_ERR_INVALID_PARAM; } @@ -392,7 +395,7 @@ tHID_STATUS HID_HostAddDev(const RawAddress& addr, uint16_t attr_mask, uint8_t* } if (i == HID_HOST_MAX_DEVICES) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_NO_RESOURCES_ADD_DEVICE, 1); return HID_ERR_NO_RESOURCES; } @@ -427,7 +430,7 @@ tHID_STATUS HID_HostRemoveDev(uint8_t dev_handle) { } if ((dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use)) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_INVALID_PARAM_AT_HOST_REMOVE_DEV, 1); return HID_ERR_INVALID_PARAM; @@ -457,13 +460,14 @@ tHID_STATUS HID_HostOpenDev(uint8_t dev_handle) { } if ((dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use)) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_INVALID_PARAM_AT_HOST_OPEN_DEV, 1); return HID_ERR_INVALID_PARAM; } if (hh_cb.devices[dev_handle].state != HID_DEV_NO_CONN) { - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_ALREADY_CONN, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_ALREADY_CONN, 1); return HID_ERR_ALREADY_CONN; } @@ -494,13 +498,13 @@ tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type, uint8_t param, if ((dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use)) { log::error("HID_ERR_INVALID_PARAM"); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_INVALID_PARAM_AT_HOST_WRITE_DEV, 1); status = HID_ERR_INVALID_PARAM; } else if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED) { log::error("HID_ERR_NO_CONNECTION dev_handle {}", dev_handle); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_NO_CONNECTION_AT_HOST_WRITE_DEV, 1); status = HID_ERR_NO_CONNECTION; @@ -530,14 +534,14 @@ tHID_STATUS HID_HostCloseDev(uint8_t dev_handle) { } if ((dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use)) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_INVALID_PARAM_AT_HOST_CLOSE_DEV, 1); return HID_ERR_INVALID_PARAM; } if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_NO_CONNECTION_AT_HOST_CLOSE_DEV, 1); return HID_ERR_NO_CONNECTION; diff --git a/system/stack/hid/hidh_conn.cc b/system/stack/hid/hidh_conn.cc index cdc7906d16..71785478a1 100644 --- a/system/stack/hid/hidh_conn.cc +++ b/system/stack/hid/hidh_conn.cc @@ -39,6 +39,7 @@ #include "internal_include/bt_target.h" #include "l2cap_types.h" #include "l2cdefs.h" +#include "main/shim/metrics_api.h" #include "osi/include/alarm.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" @@ -48,7 +49,6 @@ #include "stack/include/btm_client_interface.h" #include "stack/include/btm_log_history.h" #include "stack/include/l2cap_interface.h" -#include "stack/include/stack_metrics_logging.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -119,7 +119,7 @@ tHID_STATUS hidh_conn_reg(void) { HID_PSM_CONTROL, hst_reg_info, false /* enable_snoop */, nullptr, HID_HOST_MTU, 0, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) { log::error("HID-Host Control Registration failed"); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_L2CAP_FAILED_AT_REGISTER_CONTROL, 1); return HID_ERR_L2CAP_FAILED; @@ -129,7 +129,7 @@ tHID_STATUS hidh_conn_reg(void) { BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) { stack::l2cap::get_interface().L2CA_Deregister(HID_PSM_CONTROL); log::error("HID-Host Interrupt Registration failed"); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_L2CAP_FAILED_AT_REGISTER_INTERRUPT, 1); return HID_ERR_L2CAP_FAILED; @@ -549,7 +549,8 @@ static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) { (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) || (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) || (disc_res == HCI_ERR_REPEATED_ATTEMPTS)) { - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_AUTH_FAILED, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_AUTH_FAILED, 1); hid_close_evt_reason = HID_ERR_AUTH_FAILED; } @@ -771,14 +772,14 @@ tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type, uint8_t para if (!get_btm_client_interface().peer.BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr, BT_TRANSPORT_BR_EDR)) { osi_free(buf); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_NO_CONNECTION_AT_SEND_DATA, 1); return HID_ERR_NO_CONNECTION; } if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) { osi_free(buf); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_CONGESTED_AT_FLAG_CHECK, 1); return HID_ERR_CONGESTED; } @@ -799,7 +800,7 @@ tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type, uint8_t para buf_size = HID_INTERRUPT_BUF_SIZE; break; default: - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_INVALID_PARAM_AT_SEND_DATA, 1); return HID_ERR_INVALID_PARAM; } @@ -860,7 +861,7 @@ tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type, uint8_t para /* Send the buffer through L2CAP */ if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (stack::l2cap::get_interface().L2CA_DataWrite(cid, p_buf) == tL2CAP_DW_RESULT::FAILED)) { - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_CONGESTED_AT_SEND_DATA, 1); return HID_ERR_CONGESTED; } @@ -889,7 +890,8 @@ tHID_STATUS hidh_conn_initiate(uint8_t dhandle) { tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle]; if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) { - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_CONN_IN_PROCESS, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_CONN_IN_PROCESS, 1); return HID_ERR_CONN_IN_PROCESS; } @@ -908,7 +910,7 @@ tHID_STATUS hidh_conn_initiate(uint8_t dhandle) { log::warn("HID-Host Originate failed"); hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_L2CAP_FAILED_AT_INITIATE, 1); } else { /* Transition to the next appropriate state, waiting for connection confirm diff --git a/system/stack/include/l2cap_interface.h b/system/stack/include/l2cap_interface.h index b1551d2a80..19f85d4d2e 100644 --- a/system/stack/include/l2cap_interface.h +++ b/system/stack/include/l2cap_interface.h @@ -871,21 +871,6 @@ public: virtual void L2CA_SetEcosystemBaseInterval(uint32_t base_interval) = 0; /******************************************************************************* - * - * Function L2CA_SetDefaultSubrate - * - * Description BLE Set Default Subrate. - * - * Parameters: Subrate parameters - * - * Return value: void - * - ******************************************************************************/ - virtual void L2CA_SetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, - uint16_t max_latency, uint16_t cont_num, - uint16_t timeout) = 0; - - /******************************************************************************* ** ** Function L2CA_SetMediaStreamChannel ** diff --git a/system/stack/include/stack_metrics_logging.h b/system/stack/include/stack_metrics_logging.h deleted file mode 100644 index 9a0a80baa4..0000000000 --- a/system/stack/include/stack_metrics_logging.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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 - -#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h> -#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h> - -#include <cstdint> - -#include "hci/address.h" -#include "hci/hci_packets.h" -#include "types/raw_address.h" - -void log_classic_pairing_event(const RawAddress& address, uint16_t handle, uint32_t hci_cmd, - uint16_t hci_event, uint16_t cmd_status, uint16_t reason_code, - int64_t event_value); - -void log_link_layer_connection_event(const RawAddress* address, uint32_t connection_handle, - android::bluetooth::DirectionEnum direction, - uint16_t link_type, uint32_t hci_cmd, uint16_t hci_event, - uint16_t hci_ble_event, uint16_t cmd_status, - uint16_t reason_code); - -void log_smp_pairing_event(const RawAddress& address, uint16_t smp_cmd, - android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason); - -void log_sdp_attribute(const RawAddress& address, uint16_t protocol_uuid, uint16_t attribute_id, - size_t attribute_size, const char* attribute_value); - -void log_manufacturer_info(const RawAddress& address, - android::bluetooth::AddressTypeEnum address_type, - android::bluetooth::DeviceInfoSrcEnum source_type, - const std::string& source_name, const std::string& manufacturer, - 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); - -void log_hfp_audio_packet_loss_stats(const RawAddress& address, int num_decoded_frames, - double packet_loss_ratio, uint16_t codec_type); - -void log_mmc_transcode_rtt_stats(int maximum_rtt, double mean_rtt, int num_requests, - int codec_type); - -void log_le_pairing_fail(const RawAddress& raw_address, uint8_t failure_reason, bool is_outgoing); - -void log_le_connection_status(bluetooth::hci::Address address, bool is_connect, - bluetooth::hci::ErrorCode reason); - -void log_le_device_in_accept_list(bluetooth::hci::Address address, bool is_add); - -void log_le_connection_lifecycle(bluetooth::hci::Address address, bool is_connect, bool is_direct); - -void log_le_connection_completion(bluetooth::hci::Address address, bluetooth::hci::ErrorCode reason, - bool is_locally_initiated); diff --git a/system/stack/l2cap/internal/l2c_api.h b/system/stack/l2cap/internal/l2c_api.h index dd1dbf52e6..989eccf50e 100644 --- a/system/stack/l2cap/internal/l2c_api.h +++ b/system/stack/l2cap/internal/l2c_api.h @@ -719,20 +719,6 @@ void L2CA_SetEcosystemBaseInterval(uint32_t base_interval); /******************************************************************************* * - * Function L2CA_SetDefaultSubrate - * - * Description BLE Set Default Subrate. - * - * Parameters: Subrate parameters - * - * Return value: void - * - ******************************************************************************/ -void L2CA_SetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t timeout); - -/******************************************************************************* - * * Function L2CA_SubrateRequest * * Description BLE Subrate request. diff --git a/system/stack/l2cap/l2c_api.h b/system/stack/l2cap/l2c_api.h index 1ff09ffaf5..f9eab67d55 100644 --- a/system/stack/l2cap/l2c_api.h +++ b/system/stack/l2cap/l2c_api.h @@ -73,8 +73,6 @@ public: uint8_t* p_chnl_mask) override; [[nodiscard]] bool L2CA_SetAclPriority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) override; - void L2CA_SetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t timeout) override; void L2CA_AdjustConnectionIntervals(uint16_t* min_interval, uint16_t* max_interval, uint16_t floor_interval) override; void L2CA_SetEcosystemBaseInterval(uint32_t base_interval) override; diff --git a/system/stack/l2cap/l2c_ble.cc b/system/stack/l2cap/l2c_ble.cc index 49dca969dc..d964271002 100644 --- a/system/stack/l2cap/l2c_ble.cc +++ b/system/stack/l2cap/l2c_ble.cc @@ -1443,7 +1443,7 @@ tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t p * constraints. For example, when there is at least one Hearing Aid device * bonded, the minimum interval is raised. On return, min_interval and * max_interval are updated. */ -void L2CA_AdjustConnectionIntervals(uint16_t* min_interval, uint16_t* max_interval, +void L2CA_AdjustConnectionIntervals(uint16_t* /* min_interval */, uint16_t* max_interval, uint16_t floor_interval) { // Allow for customization by systemprops for mainline uint16_t phone_min_interval = floor_interval; @@ -1462,13 +1462,6 @@ void L2CA_AdjustConnectionIntervals(uint16_t* min_interval, uint16_t* max_interv log::verbose("Have Hearing Aids. Min. interval is set to {}", phone_min_interval); } - if (!com::android::bluetooth::flags::l2cap_le_do_not_adjust_min_interval() && - *min_interval < phone_min_interval) { - log::verbose("requested min_interval={} too small. Set to {}", *min_interval, - phone_min_interval); - *min_interval = phone_min_interval; - } - // While this could result in connection parameters that fall // outside fo the range requested, this will allow the connection // to remain established. diff --git a/system/stack/l2cap/l2c_ble_conn_params.cc b/system/stack/l2cap/l2c_ble_conn_params.cc index 49eeb06155..392b1f5a74 100644 --- a/system/stack/l2cap/l2c_ble_conn_params.cc +++ b/system/stack/l2cap/l2c_ble_conn_params.cc @@ -510,26 +510,6 @@ static void l2cble_start_subrate_change(tL2C_LCB* p_lcb) { /******************************************************************************* * - * Function L2CA_SetDefaultSubrate - * - * Description BLE Set Default Subrate - * - * Parameters: Subrate parameters - * - * Return value: void - * - ******************************************************************************/ -void L2CA_SetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t timeout) { - log::verbose("subrate_min={}, subrate_max={}, max_latency={}, cont_num={}, timeout={}", - subrate_min, subrate_max, max_latency, cont_num, timeout); - - bluetooth::shim::ACL_LeSetDefaultSubrate(subrate_min, subrate_max, max_latency, cont_num, - timeout); -} - -/******************************************************************************* - * * Function L2CA_SubrateRequest * * Description BLE Subrate request. diff --git a/system/stack/l2cap/l2cap_api.cc b/system/stack/l2cap/l2cap_api.cc index 0752c995c0..e9ccaeaf2a 100644 --- a/system/stack/l2cap/l2cap_api.cc +++ b/system/stack/l2cap/l2cap_api.cc @@ -234,13 +234,6 @@ void bluetooth::stack::l2cap::Impl::L2CA_SetEcosystemBaseInterval(uint32_t base_ return ::L2CA_IsLinkEstablished(bd_addr, transport); } -void bluetooth::stack::l2cap::Impl::L2CA_SetDefaultSubrate(uint16_t subrate_min, - uint16_t subrate_max, - uint16_t max_latency, uint16_t cont_num, - uint16_t timeout) { - ::L2CA_SetDefaultSubrate(subrate_min, subrate_max, max_latency, cont_num, timeout); -} - [[nodiscard]] bool bluetooth::stack::l2cap::Impl::L2CA_SubrateRequest( const RawAddress& rem_bda, uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t timeout) { diff --git a/system/stack/metrics/stack_metrics_logging.cc b/system/stack/metrics/stack_metrics_logging.cc deleted file mode 100644 index 398a72ce33..0000000000 --- a/system/stack/metrics/stack_metrics_logging.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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. - */ - -#include "stack/include/stack_metrics_logging.h" - -#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h> -#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h> - -#include "common/metrics.h" -#include "main/shim/metrics_api.h" -#include "main/shim/shim.h" -#include "types/raw_address.h" - -void log_classic_pairing_event(const RawAddress& address, uint16_t handle, uint32_t hci_cmd, - uint16_t hci_event, uint16_t cmd_status, uint16_t reason_code, - int64_t event_value) { - bluetooth::shim::LogMetricClassicPairingEvent(address, handle, hci_cmd, hci_event, cmd_status, - reason_code, event_value); -} - -void log_link_layer_connection_event(const RawAddress* address, uint32_t connection_handle, - android::bluetooth::DirectionEnum direction, - uint16_t link_type, uint32_t hci_cmd, uint16_t hci_event, - uint16_t hci_ble_event, uint16_t cmd_status, - uint16_t reason_code) { - bluetooth::shim::LogMetricLinkLayerConnectionEvent(address, connection_handle, direction, - link_type, hci_cmd, hci_event, hci_ble_event, - cmd_status, reason_code); -} - -void log_smp_pairing_event(const RawAddress& address, uint16_t smp_cmd, - android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) { - bluetooth::shim::LogMetricSmpPairingEvent(address, smp_cmd, direction, smp_fail_reason); -} - -void log_sdp_attribute(const RawAddress& address, uint16_t protocol_uuid, uint16_t attribute_id, - size_t attribute_size, const char* attribute_value) { - bluetooth::shim::LogMetricSdpAttribute(address, protocol_uuid, attribute_id, attribute_size, - attribute_value); -} - -void log_manufacturer_info(const RawAddress& address, - android::bluetooth::AddressTypeEnum address_type, - android::bluetooth::DeviceInfoSrcEnum source_type, - const std::string& source_name, const std::string& manufacturer, - const std::string& model, const std::string& hardware_version, - const std::string& software_version) { - bluetooth::shim::LogMetricManufacturerInfo(address, address_type, 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); -} - -void log_hfp_audio_packet_loss_stats(const RawAddress& address, int num_decoded_frames, - double packet_loss_ratio, uint16_t codec_type) { - bluetooth::shim::LogMetricHfpPacketLossStats(address, num_decoded_frames, packet_loss_ratio, - codec_type); -} - -void log_mmc_transcode_rtt_stats(int maximum_rtt, double mean_rtt, int num_requests, - int codec_type) { - bluetooth::shim::LogMetricMmcTranscodeRttStats(maximum_rtt, mean_rtt, num_requests, codec_type); -} - -void log_le_pairing_fail(const RawAddress& raw_address, uint8_t failure_reason, bool is_outgoing) { - bluetooth::shim::LogMetricLePairingFail(raw_address, failure_reason, is_outgoing); -} - -void log_le_connection_status(bluetooth::hci::Address address, bool is_connect, - bluetooth::hci::ErrorCode reason) { - bluetooth::shim::LogMetricLeConnectionStatus(address, is_connect, reason); -} - -void log_le_device_in_accept_list(bluetooth::hci::Address address, bool is_add) { - bluetooth::shim::LogMetricLeDeviceInAcceptList(address, is_add); -} - -void log_le_connection_lifecycle(bluetooth::hci::Address address, bool is_connect, bool is_direct) { - bluetooth::shim::LogMetricLeConnectionLifecycle(address, is_connect, is_direct); -} - -void log_le_connection_completion(bluetooth::hci::Address address, bluetooth::hci::ErrorCode reason, - bool is_locally_initiated) { - bluetooth::shim::LogMetricLeConnectionCompletion(address, reason, is_locally_initiated); -} diff --git a/system/stack/mmc/OWNERS b/system/stack/mmc/OWNERS deleted file mode 100644 index a823e6e1dd..0000000000 --- a/system/stack/mmc/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /OWNERS_chromeos diff --git a/system/stack/mmc/metrics/mmc_rtt_logger.cc b/system/stack/mmc/metrics/mmc_rtt_logger.cc index 761d825b44..c95566f0cb 100644 --- a/system/stack/mmc/metrics/mmc_rtt_logger.cc +++ b/system/stack/mmc/metrics/mmc_rtt_logger.cc @@ -20,7 +20,7 @@ #include <cmath> #include <string> -#include "stack/include/stack_metrics_logging.h" +#include "main/shim/metrics_api.h" namespace mmc { @@ -43,7 +43,8 @@ void MmcRttLogger::UploadTranscodeRttStatics() { if (num_requests_ == 0) { return; } - log_mmc_transcode_rtt_stats(maximum_rtt_, rtt_sum_ / num_requests_, num_requests_, codec_type_); + bluetooth::shim::LogMetricMmcTranscodeRttStats(maximum_rtt_, rtt_sum_ / num_requests_, + num_requests_, codec_type_); num_requests_ = 0; rtt_sum_ = 0; maximum_rtt_ = 0; diff --git a/system/stack/rfcomm/port_api.cc b/system/stack/rfcomm/port_api.cc index a78f3ea890..6ab7cdccea 100644 --- a/system/stack/rfcomm/port_api.cc +++ b/system/stack/rfcomm/port_api.cc @@ -1229,7 +1229,9 @@ int PORT_GetChannelInfo(uint16_t handle, uint16_t* local_mtu, uint16_t* remote_m return PORT_NOT_OPENED; } - if (p_port->line_status) { + if (p_port->rfc.p_mcb == nullptr || p_port->line_status) { + log::warn("PORT_LINE_ERR - p_port->rfc.p_mcb == nullptr:{} p_port->line_status:{}", + (p_port->rfc.p_mcb == nullptr) ? "T" : "F", p_port->line_status); return PORT_LINE_ERR; } diff --git a/system/stack/rfcomm/port_rfc.cc b/system/stack/rfcomm/port_rfc.cc index 860fdf0450..c1518665d9 100644 --- a/system/stack/rfcomm/port_rfc.cc +++ b/system/stack/rfcomm/port_rfc.cc @@ -36,12 +36,12 @@ #include "internal_include/bt_target.h" #include "internal_include/bt_trace.h" #include "main/shim/entry.h" +#include "main/shim/metrics_api.h" #include "osi/include/allocator.h" #include "osi/include/mutex.h" #include "stack/include/bt_hdr.h" #include "stack/include/bt_uuid16.h" #include "stack/include/rfc_metrics.h" -#include "stack/include/stack_metrics_logging.h" #include "stack/l2cap/l2c_int.h" #include "stack/rfcomm/port_int.h" #include "stack/rfcomm/rfc_int.h" @@ -186,7 +186,8 @@ void port_start_close(tPORT* p_port) { * clear tPort */ 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); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_START_CLOSE, 1); } port_release_port(p_port); @@ -230,7 +231,7 @@ 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( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_START_CNF_FAILED, 1); } port_release_port(p_port); @@ -457,14 +458,14 @@ void PORT_DlcEstablishInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) { if (p_port->rfc_cfg_info.data_path != BTSOCK_DATA_PATH_HARDWARE_OFFLOAD && 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); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_CONNECTION_SUCCESS_IND, 1); } } else { 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); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_CONNECTION_SUCCESS_IND, 1); } } @@ -493,7 +494,8 @@ void PORT_DlcEstablishCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint16_t if (result != RFCOMM_SUCCESS) { log::warn("Unable to establish configuration dlci:{} result:{}", dlci, result); port_rfc_closed(p_port, PORT_START_FAILED); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_START_FAILED, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_START_FAILED, 1); return; } @@ -513,14 +515,14 @@ void PORT_DlcEstablishCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint16_t if (p_port->rfc_cfg_info.data_path != BTSOCK_DATA_PATH_HARDWARE_OFFLOAD && 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); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_CONNECTION_SUCCESS_CNF, 1); } } else { 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); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_CONNECTION_SUCCESS_CNF, 1); } } @@ -590,7 +592,8 @@ void PORT_PortNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, PortSettings* /* p_settings 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); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_NEG_FAILED, 1); return; } @@ -661,7 +664,7 @@ void PORT_ControlInd(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) { if (p_port->rfc_cfg_info.data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) { if (p_port->port_ctrl == PORT_CTRL_SETUP_COMPLETED && p_port->p_mgmt_callback) { p_port->p_mgmt_callback(PORT_SUCCESS, p_port->handle); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::RFCOMM_CONNECTION_SUCCESS_IND, 1); } } @@ -708,7 +711,7 @@ void PORT_ControlCnf(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* /* p_pars */) { if (p_port->rfc_cfg_info.data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD) { if (p_port->port_ctrl == PORT_CTRL_SETUP_COMPLETED && p_port->p_mgmt_callback) { p_port->p_mgmt_callback(PORT_SUCCESS, p_port->handle); - log_counter_metrics( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::RFCOMM_CONNECTION_SUCCESS_CNF, 1); } } @@ -767,7 +770,8 @@ void PORT_DlcReleaseInd(tRFC_MCB* p_mcb, uint8_t dlci) { return; } port_rfc_closed(p_port, PORT_CLOSED); - log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_CLOSED, 1); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_CLOSED, 1); } /******************************************************************************* @@ -788,7 +792,7 @@ 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( + bluetooth::shim::CountCounterMetrics( android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_PEER_CONNECTION_FAILED, 1); } } @@ -813,7 +817,8 @@ 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); + bluetooth::shim::CountCounterMetrics( + android::bluetooth::CodePathCounterKeyEnum::RFCOMM_PORT_PEER_TIMEOUT, 1); } } } diff --git a/system/stack/rfcomm/rfc_l2cap_if.cc b/system/stack/rfcomm/rfc_l2cap_if.cc index 5b7fc00185..10826d235a 100644 --- a/system/stack/rfcomm/rfc_l2cap_if.cc +++ b/system/stack/rfcomm/rfc_l2cap_if.cc @@ -91,28 +91,26 @@ void rfcomm_l2cap_if_init(void) { void RFCOMM_ConnectInd(const RawAddress& bd_addr, uint16_t lcid, uint16_t /* psm */, uint8_t id) { tRFC_MCB* p_mcb = rfc_alloc_multiplexer_channel(bd_addr, false); - if ((p_mcb) && (p_mcb->state != RFC_MX_STATE_IDLE)) { - /* if this is collision case */ - if ((p_mcb->is_initiator) && (p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF)) { - p_mcb->pending_lcid = lcid; - - /* wait random timeout (2 - 12) to resolve collision */ - /* if peer gives up then local device rejects incoming connection and - * continues as initiator */ - /* if timeout, local device disconnects outgoing connection and continues - * as acceptor */ - log::verbose( - "RFCOMM_ConnectInd start timer for collision, initiator's " - "LCID(0x{:x}), acceptor's LCID(0x{:x})", - p_mcb->lcid, p_mcb->pending_lcid); - - rfc_timer_start(p_mcb, (uint16_t)(bluetooth::common::time_get_os_boottime_ms() % 10 + 2)); - return; - } else { - /* we cannot accept connection request from peer at this state */ - /* don't update lcid */ - p_mcb = nullptr; - } + if (p_mcb != nullptr && p_mcb->is_initiator && p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF) { + p_mcb->pending_lcid = lcid; + + /* wait random timeout (2 - 12) to resolve collision */ + /* if peer gives up then local device rejects incoming connection and + * continues as initiator */ + /* if timeout, local device disconnects outgoing connection and continues + * as acceptor */ + log::verbose( + "RFCOMM_ConnectInd start timer for collision, initiator's " + "LCID(0x{:x}), acceptor's LCID(0x{:x})", + p_mcb->lcid, p_mcb->pending_lcid); + + rfc_timer_start(p_mcb, (uint16_t)(bluetooth::common::time_get_os_boottime_ms() % 10 + 2)); + return; + } + if (p_mcb != nullptr && p_mcb->is_initiator && p_mcb->state != RFC_MX_STATE_IDLE) { + /* we cannot accept connection request from peer at this state */ + /* don't update lcid */ + p_mcb = nullptr; } else { /* store mcb even if null */ rfc_save_lcid_mcb(p_mcb, lcid); @@ -141,7 +139,7 @@ void RFCOMM_ConnectInd(const RawAddress& bd_addr, uint16_t lcid, uint16_t /* psm void RFCOMM_ConnectCnf(uint16_t lcid, tL2CAP_CONN result) { tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); - if (!p_mcb) { + if (p_mcb == nullptr) { log::error("RFCOMM_ConnectCnf LCID:0x{:x}", lcid); return; } @@ -188,7 +186,7 @@ void RFCOMM_ConfigInd(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) { tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); - if (!p_mcb) { + if (p_mcb == nullptr) { log::error("RFCOMM_ConfigInd LCID:0x{:x}", lcid); for (auto& [cid, mcb] : rfc_lcid_mcb) { if (mcb != nullptr && mcb->pending_lcid == lcid) { @@ -218,7 +216,7 @@ void RFCOMM_ConfigCnf(uint16_t lcid, uint16_t /* initiator */, tL2CAP_CFG_INFO* tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); - if (!p_mcb) { + if (p_mcb == nullptr) { log::error("RFCOMM_ConfigCnf no MCB LCID:0x{:x}", lcid); return; } @@ -237,7 +235,7 @@ void RFCOMM_ConfigCnf(uint16_t lcid, uint16_t /* initiator */, tL2CAP_CFG_INFO* void RFCOMM_DisconnectInd(uint16_t lcid, bool is_conf_needed) { log::verbose("lcid:0x{:x}, is_conf_needed:{}", lcid, is_conf_needed); tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); - if (!p_mcb) { + if (p_mcb == nullptr) { log::warn("no mcb for lcid 0x{:x}", lcid); return; } @@ -257,7 +255,7 @@ void RFCOMM_DisconnectInd(uint16_t lcid, bool is_conf_needed) { void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf) { tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); - if (!p_mcb) { + if (p_mcb == nullptr) { log::warn("Cannot find RFCOMM multiplexer for lcid 0x{:x}", lcid); osi_free(p_buf); return; @@ -351,7 +349,7 @@ void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf) { void RFCOMM_CongestionStatusInd(uint16_t lcid, bool is_congested) { tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid); - if (!p_mcb) { + if (p_mcb == nullptr) { log::error("RFCOMM_CongestionStatusInd dropped LCID:0x{:x}", lcid); return; } else { diff --git a/system/stack/sdp/sdp_utils.cc b/system/stack/sdp/sdp_utils.cc index 2fb4f4622b..324f4dd06e 100644 --- a/system/stack/sdp/sdp_utils.cc +++ b/system/stack/sdp/sdp_utils.cc @@ -39,6 +39,7 @@ #include "device/include/interop.h" #include "internal_include/bt_target.h" #include "internal_include/bt_trace.h" +#include "main/shim/metrics_api.h" #include "osi/include/allocator.h" #include "osi/include/properties.h" #include "stack/include/avrc_api.h" @@ -50,7 +51,6 @@ #include "stack/include/btm_sec_api_types.h" #include "stack/include/l2cap_interface.h" #include "stack/include/sdpdefs.h" -#include "stack/include/stack_metrics_logging.h" #include "stack/sdp/internal/sdp_api.h" #include "stack/sdp/sdpint.h" #include "storage/config_keys.h" @@ -184,15 +184,15 @@ void sdpu_log_attribute_metrics(const RawAddress& bda, tSDP_DISCOVERY_DB* p_db) } // Log the existence of a profile role // This can be different from Bluetooth Profile Descriptor List - log_sdp_attribute(bda, service_uuid, 0, 0, nullptr); + bluetooth::shim::LogMetricSdpAttribute(bda, service_uuid, 0, 0, nullptr); // Log profile version from Bluetooth Profile Descriptor List auto uuid_version_array = sdpu_find_profile_version(p_rec); for (const auto& uuid_version_pair : uuid_version_array) { uint16_t profile_uuid = uuid_version_pair.first; uint16_t version = uuid_version_pair.second; auto version_array = to_little_endian_array(version); - log_sdp_attribute(bda, profile_uuid, ATTR_ID_BT_PROFILE_DESC_LIST, version_array.size(), - version_array.data()); + bluetooth::shim::LogMetricSdpAttribute(bda, profile_uuid, ATTR_ID_BT_PROFILE_DESC_LIST, + version_array.size(), version_array.data()); } // Log protocol version from Protocol Descriptor List uint16_t protocol_uuid = 0; @@ -217,8 +217,8 @@ void sdpu_log_attribute_metrics(const RawAddress& bda, tSDP_DISCOVERY_DB* p_db) if (protocol_elements.num_params >= 1) { uint16_t version = protocol_elements.params[0]; auto version_array = to_little_endian_array(version); - log_sdp_attribute(bda, protocol_uuid, ATTR_ID_PROTOCOL_DESC_LIST, version_array.size(), - version_array.data()); + bluetooth::shim::LogMetricSdpAttribute(bda, protocol_uuid, ATTR_ID_PROTOCOL_DESC_LIST, + version_array.size(), version_array.data()); } } } @@ -238,8 +238,8 @@ void sdpu_log_attribute_metrics(const RawAddress& bda, tSDP_DISCOVERY_DB* p_db) } uint16_t supported_features = p_attr->attr_value.v.u16; auto version_array = to_little_endian_array(supported_features); - log_sdp_attribute(bda, service_uuid, ATTR_ID_SUPPORTED_FEATURES, version_array.size(), - version_array.data()); + bluetooth::shim::LogMetricSdpAttribute(bda, service_uuid, ATTR_ID_SUPPORTED_FEATURES, + version_array.size(), version_array.data()); break; } case UUID_SERVCLASS_MESSAGE_NOTIFICATION: @@ -251,8 +251,8 @@ void sdpu_log_attribute_metrics(const RawAddress& bda, tSDP_DISCOVERY_DB* p_db) } uint32_t map_supported_features = p_attr->attr_value.v.u32; auto features_array = to_little_endian_array(map_supported_features); - log_sdp_attribute(bda, service_uuid, ATTR_ID_MAP_SUPPORTED_FEATURES, features_array.size(), - features_array.data()); + bluetooth::shim::LogMetricSdpAttribute(bda, service_uuid, ATTR_ID_MAP_SUPPORTED_FEATURES, + features_array.size(), features_array.data()); break; } case UUID_SERVCLASS_PBAP_PCE: @@ -264,8 +264,8 @@ void sdpu_log_attribute_metrics(const RawAddress& bda, tSDP_DISCOVERY_DB* p_db) } uint32_t pbap_supported_features = p_attr->attr_value.v.u32; auto features_array = to_little_endian_array(pbap_supported_features); - log_sdp_attribute(bda, service_uuid, ATTR_ID_PBAP_SUPPORTED_FEATURES, features_array.size(), - features_array.data()); + bluetooth::shim::LogMetricSdpAttribute(bda, service_uuid, ATTR_ID_PBAP_SUPPORTED_FEATURES, + features_array.size(), features_array.data()); break; } } @@ -278,15 +278,17 @@ void sdpu_log_attribute_metrics(const RawAddress& bda, tSDP_DISCOVERY_DB* p_db) tSDP_DI_GET_RECORD di_record = {}; if (SDP_GetDiRecord(1, &di_record, p_db) == tSDP_STATUS::SDP_SUCCESS) { auto version_array = to_little_endian_array(di_record.spec_id); - log_sdp_attribute(bda, UUID_SERVCLASS_PNP_INFORMATION, ATTR_ID_SPECIFICATION_ID, - version_array.size(), version_array.data()); + bluetooth::shim::LogMetricSdpAttribute(bda, UUID_SERVCLASS_PNP_INFORMATION, + ATTR_ID_SPECIFICATION_ID, version_array.size(), + version_array.data()); std::stringstream ss; // [N - native]::SDP::[DIP - Device ID Profile] ss << "N:SDP::DIP::" << loghex(di_record.rec.vendor_id_source); - log_manufacturer_info(bda, android::bluetooth::AddressTypeEnum::ADDRESS_TYPE_PUBLIC, - android::bluetooth::DeviceInfoSrcEnum::DEVICE_INFO_INTERNAL, ss.str(), - loghex(di_record.rec.vendor), loghex(di_record.rec.product), - loghex(di_record.rec.version), ""); + bluetooth::shim::LogMetricManufacturerInfo( + bda, android::bluetooth::AddressTypeEnum::ADDRESS_TYPE_PUBLIC, + android::bluetooth::DeviceInfoSrcEnum::DEVICE_INFO_INTERNAL, ss.str(), + loghex(di_record.rec.vendor), loghex(di_record.rec.product), + loghex(di_record.rec.version), ""); std::string bda_string = bda.ToString(); // write manufacturer, model, HW version to config diff --git a/system/stack/smp/smp_l2c.cc b/system/stack/smp/smp_l2c.cc index 219cb723f7..69591b10e5 100644 --- a/system/stack/smp/smp_l2c.cc +++ b/system/stack/smp/smp_l2c.cc @@ -263,13 +263,6 @@ static void smp_br_connect_callback(uint16_t /* channel */, const RawAddress& bd log::info("BDA:{} pairing_bda:{}, connected:{}", bd_addr, p_cb->pairing_bda, connected); if (bd_addr != p_cb->pairing_bda) { - if (!com::android::bluetooth::flags::smp_state_machine_stuck_after_disconnection_fix()) { - log::info( - "If your pairing failed, get a build with " - "smp_state_machine_stuck_after_disconnection_fix and try again :)"); - return; - } - tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr); /* When pairing was initiated to RPA, and connection was on LE transport first using RPA, then * we must check record pseudo address, it might be same device */ diff --git a/system/stack/smp/smp_utils.cc b/system/stack/smp/smp_utils.cc index e5aefe3c6a..9be3de7db1 100644 --- a/system/stack/smp/smp_utils.cc +++ b/system/stack/smp/smp_utils.cc @@ -35,6 +35,7 @@ #include "internal_include/stack_config.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" +#include "main/shim/metrics_api.h" #include "metrics/bluetooth_event.h" #include "osi/include/allocator.h" #include "p_256_ecc_pp.h" @@ -51,7 +52,6 @@ #include "stack/include/l2cap_interface.h" #include "stack/include/l2cdefs.h" #include "stack/include/smp_status.h" -#include "stack/include/stack_metrics_logging.h" #include "types/raw_address.h" #define SMP_PAIRING_REQ_SIZE 7 @@ -320,7 +320,7 @@ void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing, const uint8_t* uint8_t failure_reason = 0; if (raw_cmd == SMP_OPCODE_PAIRING_FAILED && buf_len >= 1) { STREAM_TO_UINT8(failure_reason, p_buf); - log_le_pairing_fail(bd_addr, failure_reason, is_outgoing); + bluetooth::shim::LogMetricLePairingFail(bd_addr, failure_reason, is_outgoing); } if (smp_cb.is_pair_cancel) { failure_reason = SMP_USER_CANCELLED; // Tracking pairing cancellations @@ -330,7 +330,8 @@ void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing, const uint8_t* android::bluetooth::DirectionEnum direction = is_outgoing ? android::bluetooth::DirectionEnum::DIRECTION_OUTGOING : android::bluetooth::DirectionEnum::DIRECTION_INCOMING; - log_smp_pairing_event(bd_addr, metric_cmd, direction, static_cast<uint16_t>(failure_reason)); + bluetooth::shim::LogMetricSmpPairingEvent(bd_addr, metric_cmd, direction, + static_cast<uint16_t>(failure_reason)); } /******************************************************************************* @@ -1011,7 +1012,8 @@ void smp_proc_pairing_cmpl(tSMP_CB* p_cb) { if (metric_status > SMP_MAX_FAIL_RSN_PER_SPEC) { metric_status |= SMP_METRIC_STATUS_INTERNAL_FLAG; } - log_smp_pairing_event(p_cb->pairing_bda, metric_cmd, direction, metric_status); + bluetooth::shim::LogMetricSmpPairingEvent(p_cb->pairing_bda, metric_cmd, direction, + metric_status); } if (p_cb->status == SMP_SUCCESS && p_cb->smp_over_br) { diff --git a/system/stack/test/btm/stack_btm_power_mode_test.cc b/system/stack/test/btm/stack_btm_power_mode_test.cc index a3376d8649..ad7b27a71a 100644 --- a/system/stack/test/btm/stack_btm_power_mode_test.cc +++ b/system/stack/test/btm/stack_btm_power_mode_test.cc @@ -49,8 +49,10 @@ std::deque<power_mode_callback> power_mode_callback_queue; class StackBtmPowerMode : public testing::Test { protected: void SetUp() override { - ON_CALL(controller_, SupportsSniffMode).WillByDefault(Return(true)); - bluetooth::hci::testing::mock_controller_ = &controller_; + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); + ON_CALL(*bluetooth::hci::testing::mock_controller_, SupportsSniffMode) + .WillByDefault(Return(true)); power_mode_callback_queue.clear(); reset_mock_function_count_map(); ASSERT_EQ(tBTM_STATUS::BTM_SUCCESS, @@ -71,10 +73,9 @@ protected: BTM_PmRegister(BTM_PM_DEREG, &pm_id_, [](const RawAddress& /* p_bda */, tBTM_PM_STATUS /* status */, uint16_t /* value */, tHCI_STATUS /* hci_status */) {})); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); } - bluetooth::hci::testing::MockControllerInterface controller_; uint8_t pm_id_{0}; }; diff --git a/system/stack/test/btm/stack_btm_sec_test.cc b/system/stack/test/btm/stack_btm_sec_test.cc index 58317afc29..62226e2750 100644 --- a/system/stack/test/btm/stack_btm_sec_test.cc +++ b/system/stack/test/btm/stack_btm_sec_test.cc @@ -69,7 +69,8 @@ protected: down_thread_ = new bluetooth::os::Thread("down_thread", bluetooth::os::Thread::Priority::NORMAL); down_handler_ = new bluetooth::os::Handler(down_thread_); - bluetooth::hci::testing::mock_hci_layer_ = &mock_hci_; + bluetooth::hci::testing::mock_hci_layer_ = + std::make_unique<bluetooth::hci::testing::MockHciLayer>(); bluetooth::hci::testing::mock_gd_shim_handler_ = up_handler_; } void TearDown() override { @@ -79,10 +80,10 @@ protected: down_handler_->Clear(); delete down_handler_; delete down_thread_; + bluetooth::hci::testing::mock_hci_layer_.reset(); StackBtmSecTest::TearDown(); } bluetooth::common::BidiQueue<bluetooth::hci::ScoView, bluetooth::hci::ScoBuilder> sco_queue_{10}; - bluetooth::hci::testing::MockHciLayer mock_hci_; bluetooth::os::Thread* up_thread_; bluetooth::os::Handler* up_handler_; bluetooth::os::Thread* down_thread_; diff --git a/system/stack/test/btm/stack_btm_test.cc b/system/stack/test/btm/stack_btm_test.cc index 7471d4faca..2341b21677 100644 --- a/system/stack/test/btm/stack_btm_test.cc +++ b/system/stack/test/btm/stack_btm_test.cc @@ -63,13 +63,13 @@ public: protected: void SetUp() override { BtmWithMocksTest::SetUp(); - bluetooth::hci::testing::mock_controller_ = &controller_; + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); } void TearDown() override { - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); BtmWithMocksTest::TearDown(); } - bluetooth::hci::testing::MockControllerInterface controller_; }; class StackBtmWithQueuesTest : public StackBtmTest { @@ -82,11 +82,12 @@ protected: down_thread_ = new bluetooth::os::Thread("down_thread", bluetooth::os::Thread::Priority::NORMAL); down_handler_ = new bluetooth::os::Handler(down_thread_); - bluetooth::hci::testing::mock_hci_layer_ = &mock_hci_; + bluetooth::hci::testing::mock_hci_layer_ = + std::make_unique<bluetooth::hci::testing::MockHciLayer>(); bluetooth::hci::testing::mock_gd_shim_handler_ = up_handler_; bluetooth::legacy::hci::testing::SetMock(legacy_hci_mock_); - EXPECT_CALL(mock_hci_, RegisterForScoConnectionRequests(_)); - EXPECT_CALL(mock_hci_, RegisterForDisconnects(_)); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, RegisterForScoConnectionRequests(_)); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, RegisterForDisconnects(_)); } void TearDown() override { up_handler_->Clear(); @@ -95,10 +96,10 @@ protected: down_handler_->Clear(); delete down_handler_; delete down_thread_; + bluetooth::hci::testing::mock_hci_layer_.release(); StackBtmTest::TearDown(); } bluetooth::common::BidiQueue<bluetooth::hci::ScoView, bluetooth::hci::ScoBuilder> sco_queue_{10}; - bluetooth::hci::testing::MockHciLayer mock_hci_; bluetooth::legacy::hci::testing::MockInterface legacy_hci_mock_; bluetooth::os::Thread* up_thread_; bluetooth::os::Handler* up_handler_; @@ -111,7 +112,8 @@ public: protected: void SetUp() override { StackBtmWithQueuesTest::SetUp(); - EXPECT_CALL(mock_hci_, GetScoQueueEnd()).WillOnce(Return(sco_queue_.GetUpEnd())); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); btm_cb.Init(); btm_sec_cb.Init(BTM_SEC_MODE_SC); } @@ -123,7 +125,8 @@ protected: }; TEST_F(StackBtmWithQueuesTest, GlobalLifecycle) { - EXPECT_CALL(mock_hci_, GetScoQueueEnd()).WillOnce(Return(sco_queue_.GetUpEnd())); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); get_btm_client_interface().lifecycle.btm_init(); get_btm_client_interface().lifecycle.btm_free(); } @@ -134,20 +137,23 @@ TEST_F(StackBtmTest, DynamicLifecycle) { } TEST_F(StackBtmWithQueuesTest, InitFree) { - EXPECT_CALL(mock_hci_, GetScoQueueEnd()).WillOnce(Return(sco_queue_.GetUpEnd())); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); btm_cb.Init(); btm_cb.Free(); } TEST_F(StackBtmWithQueuesTest, tSCO_CB) { - EXPECT_CALL(mock_hci_, GetScoQueueEnd()).WillOnce(Return(sco_queue_.GetUpEnd())); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); tSCO_CB* p_sco = &btm_cb.sco_cb; p_sco->Init(); p_sco->Free(); } TEST_F(StackBtmWithQueuesTest, InformClientOnConnectionSuccess) { - EXPECT_CALL(mock_hci_, GetScoQueueEnd()).WillOnce(Return(sco_queue_.GetUpEnd())); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); get_btm_client_interface().lifecycle.btm_init(); RawAddress bda({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); @@ -159,7 +165,8 @@ TEST_F(StackBtmWithQueuesTest, InformClientOnConnectionSuccess) { } TEST_F(StackBtmWithQueuesTest, NoInformClientOnConnectionFail) { - EXPECT_CALL(mock_hci_, GetScoQueueEnd()).WillOnce(Return(sco_queue_.GetUpEnd())); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); get_btm_client_interface().lifecycle.btm_init(); RawAddress bda({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); @@ -171,7 +178,8 @@ TEST_F(StackBtmWithQueuesTest, NoInformClientOnConnectionFail) { } TEST_F(StackBtmWithQueuesTest, default_packet_type) { - EXPECT_CALL(mock_hci_, GetScoQueueEnd()).WillOnce(Return(sco_queue_.GetUpEnd())); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); get_btm_client_interface().lifecycle.btm_init(); btm_cb.acl_cb_.SetDefaultPacketTypeMask(0x4321); @@ -181,7 +189,8 @@ TEST_F(StackBtmWithQueuesTest, default_packet_type) { } TEST_F(StackBtmWithQueuesTest, change_packet_type) { - EXPECT_CALL(mock_hci_, GetScoQueueEnd()).WillOnce(Return(sco_queue_.GetUpEnd())); + EXPECT_CALL(*bluetooth::hci::testing::mock_hci_layer_, GetScoQueueEnd()) + .WillOnce(Return(sco_queue_.GetUpEnd())); get_btm_client_interface().lifecycle.btm_init(); uint16_t handle = 0x123; diff --git a/system/stack/test/btm_iso_test.cc b/system/stack/test/btm_iso_test.cc index 40453f703d..b44f6fe094 100644 --- a/system/stack/test/btm_iso_test.cc +++ b/system/stack/test/btm_iso_test.cc @@ -134,7 +134,8 @@ protected: bluetooth::shim::SetMockIsoInterface(&iso_interface_); hcic::SetMockHcicInterface(&hcic_interface_); bluetooth::shim::testing::hci_layer_set_interface(&bluetooth::shim::interface); - bluetooth::hci::testing::mock_controller_ = &controller_; + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); big_callbacks_.reset(new MockBigCallbacks()); cig_callbacks_.reset(new MockCigCallbacks()); @@ -142,7 +143,8 @@ protected: iso_sizes_.total_num_le_packets_ = 6; iso_sizes_.le_data_packet_length_ = 1024; - ON_CALL(controller_, GetControllerIsoBufferSize()).WillByDefault(Return(iso_sizes_)); + ON_CALL(*bluetooth::hci::testing::mock_controller_, GetControllerIsoBufferSize()) + .WillByDefault(Return(iso_sizes_)); InitIsoManager(); } @@ -156,7 +158,7 @@ protected: bluetooth::shim::SetMockIsoInterface(nullptr); hcic::SetMockHcicInterface(nullptr); bluetooth::shim::testing::hci_layer_set_interface(nullptr); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); } virtual void InitIsoManager() { @@ -312,7 +314,6 @@ protected: IsoManager* manager_instance_; bluetooth::shim::MockIsoInterface iso_interface_; hcic::MockHcicInterface hcic_interface_; - bluetooth::hci::testing::MockControllerInterface controller_; bluetooth::hci::LeBufferSize iso_sizes_; std::unique_ptr<MockBigCallbacks> big_callbacks_; @@ -2207,7 +2208,8 @@ TEST_F(IsoManagerTest, SendIsoDataBigValid) { } TEST_F(IsoManagerTest, SendIsoDataNoCredits) { - uint8_t num_buffers = controller_.GetControllerIsoBufferSize().total_num_le_packets_; + uint8_t num_buffers = bluetooth::hci::testing::mock_controller_->GetControllerIsoBufferSize() + .total_num_le_packets_; std::vector<uint8_t> data_vec(108, 0); // Check on CIG @@ -2254,7 +2256,8 @@ TEST_F(IsoManagerTest, SendIsoDataNoCredits) { } TEST_F(IsoManagerTest, SendIsoDataCreditsReturned) { - uint8_t num_buffers = controller_.GetControllerIsoBufferSize().total_num_le_packets_; + uint8_t num_buffers = bluetooth::hci::testing::mock_controller_->GetControllerIsoBufferSize() + .total_num_le_packets_; std::vector<uint8_t> data_vec(108, 0); // Check on CIG @@ -2323,7 +2326,8 @@ TEST_F(IsoManagerTest, SendIsoDataCreditsReturned) { } TEST_F(IsoManagerTest, SendIsoDataCreditsReturnedByDisconnection) { - uint8_t num_buffers = controller_.GetControllerIsoBufferSize().total_num_le_packets_; + uint8_t num_buffers = bluetooth::hci::testing::mock_controller_->GetControllerIsoBufferSize() + .total_num_le_packets_; std::vector<uint8_t> data_vec(108, 0); // Check on CIG @@ -2542,7 +2546,8 @@ TEST_F(IsoManagerDeathTestNoCleanup, HandleLateArivingEventHandleDisconnect) { * is already stopped. */ TEST_F(IsoManagerDeathTestNoCleanup, HandleLateArivingEventHandleNumComplDataPkts) { - uint8_t num_buffers = controller_.GetControllerIsoBufferSize().total_num_le_packets_; + uint8_t num_buffers = bluetooth::hci::testing::mock_controller_->GetControllerIsoBufferSize() + .total_num_le_packets_; IsoManager::GetInstance()->CreateCig(volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams); diff --git a/system/stack/test/connection_manager_test.cc b/system/stack/test/connection_manager_test.cc index 1a06158ca0..db2908c76b 100644 --- a/system/stack/test/connection_manager_test.cc +++ b/system/stack/test/connection_manager_test.cc @@ -70,9 +70,10 @@ namespace connection_manager { class BleConnectionManager : public testing::Test { void SetUp() override { localConnTimeoutMock = std::make_unique<MockConnTimeout>(); - /* extern */ test::mock_acl_manager_ = new bluetooth::hci::testing::MockAclManager(); + /* extern */ test::mock_acl_manager_ = + std::make_unique<bluetooth::hci::testing::MockAclManager>(); /* extern */ test::mock_controller_ = - new testing::NiceMock<bluetooth::hci::testing::MockControllerInterface>(); + std::make_unique<testing::NiceMock<bluetooth::hci::testing::MockControllerInterface>>(); ON_CALL(*test::mock_controller_, GetLeFilterAcceptListSize()).WillByDefault(Return(16)); auto alarm_mock = AlarmMock::Get(); @@ -92,8 +93,8 @@ class BleConnectionManager : public testing::Test { void TearDown() override { connection_manager::reset(true); AlarmMock::Reset(); - delete test::mock_controller_; - delete test::mock_acl_manager_; + test::mock_controller_.reset(); + test::mock_acl_manager_.reset(); localConnTimeoutMock.reset(); } }; @@ -106,7 +107,7 @@ TEST_F(BleConnectionManager, test_background_connection_add_remove) { EXPECT_TRUE(background_connect_add(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); std::set<tAPP_ID> apps = get_apps_connecting_to(address1); EXPECT_EQ(apps.size(), 1UL); @@ -119,7 +120,7 @@ TEST_F(BleConnectionManager, test_background_connection_add_remove) { EXPECT_EQ(get_apps_connecting_to(address1).size(), 0UL); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } /** Verify that multiple clients adding same device multiple times, result in @@ -136,7 +137,7 @@ TEST_F(BleConnectionManager, test_background_connection_multiple_clients) { EXPECT_EQ(get_apps_connecting_to(address1).size(), 3UL); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*test::mock_acl_manager_, CreateLeConnection(_, _)).Times(0); @@ -153,7 +154,7 @@ TEST_F(BleConnectionManager, test_background_connection_multiple_clients) { EXPECT_EQ(get_apps_connecting_to(address1).size(), 0UL); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } /** Verify adding/removing device to direct connection. */ @@ -173,7 +174,7 @@ TEST_F(BleConnectionManager, test_direct_connection_client) { // Client that don't do direct connection should fail attempt to stop it EXPECT_FALSE(direct_connect_remove(CLIENT2, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*test::mock_acl_manager_, CancelLeConnect(_)).Times(1); EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1); @@ -183,7 +184,7 @@ TEST_F(BleConnectionManager, test_direct_connection_client) { // acceptlist is in use, i.e. next connection attempt EXPECT_TRUE(direct_connect_remove(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } /** Verify direct connection timeout does remove device from acceptlist, and @@ -201,7 +202,7 @@ TEST_F(BleConnectionManager, test_direct_connect_timeout) { // Start direct connect attempt... EXPECT_TRUE(direct_connect_add(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*test::mock_acl_manager_, CancelLeConnect(_)).Times(1); EXPECT_CALL(*localConnTimeoutMock, OnConnectionTimedOut(CLIENT1, address1)).Times(1); @@ -210,7 +211,7 @@ TEST_F(BleConnectionManager, test_direct_connect_timeout) { // simulate timeout seconds passed, alarm executing alarm_callback(alarm_data); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } /** Verify that we properly handle successfull direct connection */ @@ -222,7 +223,7 @@ TEST_F(BleConnectionManager, test_direct_connection_success) { // Start direct connect attempt... EXPECT_TRUE(direct_connect_add(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*test::mock_acl_manager_, CancelLeConnect(address1_hci)).Times(1); EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1); @@ -230,7 +231,7 @@ TEST_F(BleConnectionManager, test_direct_connection_success) { // successfully. on_connection_complete(address1); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } /** Verify that we properly handle application unregistration */ @@ -244,23 +245,23 @@ TEST_F(BleConnectionManager, test_app_unregister) { EXPECT_CALL(*test::mock_acl_manager_, CreateLeConnection(address1_hci, true)).Times(1); EXPECT_TRUE(direct_connect_add(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*test::mock_acl_manager_, CreateLeConnection(address2_hci, false)).Times(1); EXPECT_TRUE(background_connect_add(CLIENT1, address2)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*test::mock_acl_manager_, CreateLeConnection(address2_hci, true)).Times(1); EXPECT_TRUE(direct_connect_add(CLIENT2, address2)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*test::mock_acl_manager_, CancelLeConnect(address1_hci)).Times(1); on_app_deregistered(CLIENT1); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*test::mock_acl_manager_, CancelLeConnect(address2_hci)).Times(1); on_app_deregistered(CLIENT2); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } /** Verify adding device to both direct connection and background connection. */ @@ -273,7 +274,7 @@ TEST_F(BleConnectionManager, test_direct_and_background_connect) { EXPECT_TRUE(direct_connect_add(CLIENT1, address1)); EXPECT_TRUE(background_connect_add(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1); // not removing from acceptlist yet, as the background connection is still @@ -284,7 +285,7 @@ TEST_F(BleConnectionManager, test_direct_and_background_connect) { EXPECT_CALL(*test::mock_acl_manager_, CancelLeConnect(_)).Times(1); EXPECT_TRUE(background_connect_remove(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } TEST_F(BleConnectionManager, test_target_announement_connect) { @@ -302,7 +303,7 @@ TEST_F(BleConnectionManager, test_add_targeted_announement_when_allow_list_used) EXPECT_TRUE(background_connect_add(CLIENT1, address1)); EXPECT_TRUE(background_connect_targeted_announcement_add(CLIENT2, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } TEST_F(BleConnectionManager, test_add_background_connect_when_targeted_announcement_are_enabled) { @@ -315,7 +316,7 @@ TEST_F(BleConnectionManager, test_add_background_connect_when_targeted_announcem EXPECT_TRUE(background_connect_targeted_announcement_add(CLIENT2, address1)); EXPECT_TRUE(background_connect_add(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } TEST_F(BleConnectionManager, test_re_add_background_connect_to_allow_list) { @@ -325,7 +326,7 @@ TEST_F(BleConnectionManager, test_re_add_background_connect_to_allow_list) { EXPECT_TRUE(background_connect_targeted_announcement_add(CLIENT2, address1)); EXPECT_TRUE(background_connect_add(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); /* Now remove app using targeted announcement and expect device * to be added to white list @@ -335,11 +336,11 @@ TEST_F(BleConnectionManager, test_re_add_background_connect_to_allow_list) { EXPECT_CALL(*test::mock_acl_manager_, CreateLeConnection(address1_hci, false)).Times(1); EXPECT_TRUE(background_connect_remove(CLIENT2, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*test::mock_acl_manager_, CancelLeConnect(_)).Times(1); EXPECT_TRUE(background_connect_remove(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } TEST_F(BleConnectionManager, test_re_add_to_allow_list_after_timeout_with_multiple_clients) { @@ -352,7 +353,7 @@ TEST_F(BleConnectionManager, test_re_add_to_allow_list_after_timeout_with_multip EXPECT_TRUE(background_connect_add(CLIENT1, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); EXPECT_CALL(*AlarmMock::Get(), AlarmSetOnMloop(_, _, _, _)) .Times(1) @@ -360,7 +361,7 @@ TEST_F(BleConnectionManager, test_re_add_to_allow_list_after_timeout_with_multip // Start direct connect attempt... EXPECT_TRUE(direct_connect_add(CLIENT2, address1)); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); // simulate timeout seconds passed, alarm executing EXPECT_CALL(*localConnTimeoutMock, OnConnectionTimedOut(CLIENT2, address1)).Times(1); @@ -369,7 +370,7 @@ TEST_F(BleConnectionManager, test_re_add_to_allow_list_after_timeout_with_multip EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1); alarm_callback(alarm_data); - Mock::VerifyAndClearExpectations(test::mock_acl_manager_); + Mock::VerifyAndClearExpectations(test::mock_acl_manager_.get()); } } // namespace connection_manager diff --git a/system/stack/test/eatt/eatt_test.cc b/system/stack/test/eatt/eatt_test.cc index 130893a0a5..17f4908b3e 100644 --- a/system/stack/test/eatt/eatt_test.cc +++ b/system/stack/test/eatt/eatt_test.cc @@ -219,11 +219,13 @@ protected: le_buffer_size_.le_data_packet_length_ = 128; le_buffer_size_.total_num_le_packets_ = 24; - EXPECT_CALL(controller_, GetLeBufferSize).WillRepeatedly(Return(le_buffer_size_)); + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); + EXPECT_CALL(*bluetooth::hci::testing::mock_controller_, GetLeBufferSize) + .WillRepeatedly(Return(le_buffer_size_)); bluetooth::l2cap::SetMockInterface(&l2cap_interface_); bluetooth::manager::SetMockBtmApiInterface(&btm_api_interface_); bluetooth::gatt::SetMockGattInterface(&gatt_interface_); - bluetooth::hci::testing::mock_controller_ = &controller_; // Clear the static memory for each test case memset(&test_tcb, 0, sizeof(test_tcb)); @@ -258,7 +260,7 @@ protected: bluetooth::l2cap::SetMockInterface(nullptr); bluetooth::testing::stack::l2cap::reset_interface(); bluetooth::manager::SetMockBtmApiInterface(nullptr); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); Test::TearDown(); } @@ -269,7 +271,6 @@ protected: bluetooth::l2cap::MockL2capInterface l2cap_interface_; bluetooth::testing::stack::l2cap::Mock mock_stack_l2cap_interface_; bluetooth::gatt::MockGattInterface gatt_interface_; - bluetooth::hci::testing::MockControllerInterface controller_; bluetooth::hci::LeBufferSize le_buffer_size_; tL2CAP_APPL_INFO l2cap_app_info_; @@ -659,7 +660,6 @@ TEST_F(EattTest, ChannelUnavailableWhileReconfiguring) { } TEST_F(EattTest, DisconnectChannelOnIndicationConfirmationTimeout) { - com::android::bluetooth::flags::provider_->gatt_disconnect_fix(true); ConnectDeviceEattSupported(1); eatt_instance_->StartIndicationConfirmationTimer(test_address, test_local_cids[0]); diff --git a/system/stack/test/gatt/gatt_sr_test.cc b/system/stack/test/gatt/gatt_sr_test.cc index 9c5eb868d0..4106579080 100644 --- a/system/stack/test/gatt/gatt_sr_test.cc +++ b/system/stack/test/gatt/gatt_sr_test.cc @@ -14,7 +14,6 @@ * limitations under the License. */ -#include <com_android_bluetooth_flags.h> #include <gtest/gtest.h> #include <cstdint> @@ -141,25 +140,16 @@ protected: tcb_.att_lcid = L2CAP_ATT_CID; el_.gatt_if = 1; - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - gatt_cb.cl_rcb_map.emplace(el_.gatt_if, std::make_unique<tGATT_REG>()); - tGATT_REG* p_reg = gatt_cb.cl_rcb_map[el_.gatt_if].get(); - p_reg->in_use = true; - p_reg->gatt_if = el_.gatt_if; - p_reg->app_cb.p_req_cb = ApplicationRequestCallback; - } else { - gatt_cb.cl_rcb[el_.gatt_if - 1].in_use = true; - gatt_cb.cl_rcb[el_.gatt_if - 1].app_cb.p_req_cb = ApplicationRequestCallback; - } + gatt_cb.cl_rcb_map.emplace(el_.gatt_if, std::make_unique<tGATT_REG>()); + tGATT_REG* p_reg = gatt_cb.cl_rcb_map[el_.gatt_if].get(); + p_reg->in_use = true; + p_reg->gatt_if = el_.gatt_if; + p_reg->app_cb.p_req_cb = ApplicationRequestCallback; test_state_ = TestMutables(); } - void TearDown() override { - if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { - gatt_cb.cl_rcb_map.erase(el_.gatt_if); - } - } + void TearDown() override { gatt_cb.cl_rcb_map.erase(el_.gatt_if); } tGATT_TCB tcb_; tGATT_SRV_LIST_ELEM el_; diff --git a/system/stack/test/sdp/stack_sdp_test.cc b/system/stack/test/sdp/stack_sdp_test.cc index 314ea02334..c792a5fd0d 100644 --- a/system/stack/test/sdp/stack_sdp_test.cc +++ b/system/stack/test/sdp/stack_sdp_test.cc @@ -62,7 +62,6 @@ protected: fake_osi_ = std::make_unique<test::fake::FakeOsi>(); bluetooth::testing::stack::l2cap::set_interface(&mock_stack_l2cap_interface_); - tL2CAP_APPL_INFO l2cap_callbacks{}; EXPECT_CALL(mock_stack_l2cap_interface_, L2CA_RegisterWithSecurity(_, _, _, _, _, _, _)) .WillOnce(DoAll(SaveArg<1>(&l2cap_callbacks), ::testing::ReturnArg<0>())); EXPECT_CALL(mock_stack_l2cap_interface_, L2CA_Deregister(_)); @@ -73,6 +72,7 @@ protected: fake_osi_.reset(); } + tL2CAP_APPL_INFO l2cap_callbacks{}; bluetooth::testing::stack::l2cap::Mock mock_stack_l2cap_interface_; std::unique_ptr<test::fake::FakeOsi> fake_osi_; }; diff --git a/system/stack/test/stack_acl_test.cc b/system/stack/test/stack_acl_test.cc index b08a45cb80..bd0b153b9f 100644 --- a/system/stack/test/stack_acl_test.cc +++ b/system/stack/test/stack_acl_test.cc @@ -48,12 +48,12 @@ class StackAclTest : public testing::Test { protected: void SetUp() override { reset_mock_function_count_map(); - bluetooth::hci::testing::mock_controller_ = &controller_; + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); } - void TearDown() override { bluetooth::hci::testing::mock_controller_ = nullptr; } + void TearDown() override { bluetooth::hci::testing::mock_controller_.reset(); } tBTM_SEC_DEV_REC device_record_; - bluetooth::hci::testing::MockControllerInterface controller_; }; TEST_F(StackAclTest, nop) {} diff --git a/system/stack/test/stack_l2cap_test.cc b/system/stack/test/stack_l2cap_test.cc index ffe78055bc..204900b462 100644 --- a/system/stack/test/stack_l2cap_test.cc +++ b/system/stack/test/stack_l2cap_test.cc @@ -49,23 +49,23 @@ constexpr uint16_t kAclBufferSizeBle = 45; class StackL2capTest : public ::testing::Test { protected: void SetUp() override { - bluetooth::hci::testing::mock_controller_ = &controller_interface_; - ON_CALL(controller_interface_, GetNumAclPacketBuffers) + bluetooth::hci::testing::mock_controller_ = + std::make_unique<bluetooth::hci::testing::MockControllerInterface>(); + ON_CALL(*bluetooth::hci::testing::mock_controller_, GetNumAclPacketBuffers) .WillByDefault(Return(kAclBufferCountClassic)); bluetooth::hci::LeBufferSize le_sizes; le_sizes.total_num_le_packets_ = kAclBufferCountBle; le_sizes.le_data_packet_length_ = kAclBufferSizeBle; - ON_CALL(controller_interface_, GetLeBufferSize).WillByDefault(Return(le_sizes)); - ON_CALL(controller_interface_, SupportsBle).WillByDefault(Return(true)); + ON_CALL(*bluetooth::hci::testing::mock_controller_, GetLeBufferSize) + .WillByDefault(Return(le_sizes)); + ON_CALL(*bluetooth::hci::testing::mock_controller_, SupportsBle).WillByDefault(Return(true)); l2c_init(); } void TearDown() override { l2c_free(); - bluetooth::hci::testing::mock_controller_ = nullptr; + bluetooth::hci::testing::mock_controller_.reset(); } - - bluetooth::hci::testing::MockControllerInterface controller_interface_; }; TEST_F(StackL2capTest, l2cble_process_data_length_change_event) { diff --git a/system/test/Android.bp b/system/test/Android.bp index c35931ea17..9dab01352f 100644 --- a/system/test/Android.bp +++ b/system/test/Android.bp @@ -88,6 +88,13 @@ filegroup { } filegroup { + name: "TestMockBtaHearingAidAudioSource", + srcs: [ + "mock/mock_bta_hearing_aid_audio_source.cc", + ], +} + +filegroup { name: "TestMockBtaHf", srcs: [ "mock/mock_bta_hf*.cc", @@ -184,6 +191,7 @@ filegroup { ":TestMockBtaHas", ":TestMockBtaHd", ":TestMockBtaHearingAid", + ":TestMockBtaHearingAidAudioSource", ":TestMockBtaHf", ":TestMockBtaHh", ":TestMockBtaJv", @@ -450,16 +458,16 @@ filegroup { } filegroup { - name: "TestMockStackMetrics", + name: "TestMockStackGap", srcs: [ - "mock/mock_stack_metrics*.cc", + "mock/mock_stack_gap*.cc", ], } filegroup { - name: "TestMockStackGap", + name: "TestMockStackGapConnInterface", srcs: [ - "mock/mock_stack_gap*.cc", + "mock/mock_stack_gap_conn_interface.cc", ], } diff --git a/system/test/README.md b/system/test/README.md deleted file mode 100644 index 1f43e952ef..0000000000 --- a/system/test/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Fluoride Bluetooth Tests - -This document refers to the tests in the packages/modules/Bluetooth/system/test directory. - -The tests are designed to be run when the Android runtime is not running. From a terminal, run: - -## Before you run tests -```sh -adb shell stop -``` - -## After you're done -```sh -adb shell start -``` - -## Running tests -Then see what options the test script provides: - -```sh -./run_unit_tests.sh --help -``` - -But for the impatient, run specific groups of tests like this: - -```sh -./run_unit_tests.sh net_test_bluetooth -``` - -a single test: - -```sh -./run_unit_tests.sh net_test_bluetooth.BluetoothTest.AdapterRepeatedEnableDisable -``` - -## Sample Output - -packages/modules/Bluetooth/system/test$ ./run_unit_tests.sh net_test_bluetooth ---- net_test_bluetooth --- -pushing... -/tbd/aosp-master/out/target/product/bullhead/data/nativetest/n...st_bluetooth: 1 file pushed. 9.2 MB/s (211832 bytes in 0.022s) -running... - -Running main() from gtest_main.cc -[==========] Running 11 tests from 2 test cases. -[----------] Global test environment set-up. -[----------] 6 tests from BluetoothTest -[ RUN ] BluetoothTest.AdapterEnableDisable -[ OK ] BluetoothTest.AdapterEnableDisable (2538 ms) -[ RUN ] BluetoothTest.AdapterRepeatedEnableDisable -[ OK ] BluetoothTest.AdapterRepeatedEnableDisable (11384 ms) -[ RUN ] BluetoothTest.AdapterSetGetName -[ OK ] BluetoothTest.AdapterSetGetName (2378 ms) -[ RUN ] BluetoothTest.AdapterStartDiscovery -[ OK ] BluetoothTest.AdapterStartDiscovery (2397 ms) -[ RUN ] BluetoothTest.AdapterCancelDiscovery -[ OK ] BluetoothTest.AdapterCancelDiscovery (2401 ms) -[ RUN ] BluetoothTest.AdapterDisableDuringBonding -[ OK ] BluetoothTest.AdapterDisableDuringBonding (11689 ms) -[----------] 6 tests from BluetoothTest (32789 ms total) - -[----------] 5 tests from GattTest -[ RUN ] GattTest.GattClientRegister -[ OK ] GattTest.GattClientRegister (2370 ms) -[ RUN ] GattTest.GattClientScanRemoteDevice -[ OK ] GattTest.GattClientScanRemoteDevice (2273 ms) -[ RUN ] GattTest.GattClientAdvertise -[ OK ] GattTest.GattClientAdvertise (2236 ms) -[ RUN ] GattTest.GattServerRegister -[ OK ] GattTest.GattServerRegister (2391 ms) -[ RUN ] GattTest.GattServerBuild -[ OK ] GattTest.GattServerBuild (2435 ms) -[----------] 5 tests from GattTest (11706 ms total) - -[----------] Global test environment tear-down -[==========] 11 tests from 2 test cases ran. (44495 ms total) -[ PASSED ] 11 tests. - -## Troubleshooting: Your phone is bricked! -Probably not. See [After you're done](#After-you're-done) - diff --git a/system/test/mock/mock_bta_hearing_aid_audio_source.cc b/system/test/mock/mock_bta_hearing_aid_audio_source.cc new file mode 100644 index 0000000000..c68fad3b8d --- /dev/null +++ b/system/test/mock/mock_bta_hearing_aid_audio_source.cc @@ -0,0 +1,43 @@ +/* + * 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:8 + */ + +#include <base/functional/callback.h> + +#include <cstdint> + +#include "bta/include/bta_gatt_queue.h" +#include "bta/include/bta_hearing_aid_api.h" +#include "test/common/mock_functions.h" +#include "types/raw_address.h" + +void HearingAidAudioSource::Start(const CodecConfiguration& /*codecConfiguration*/, + HearingAidAudioReceiver* /*audioReceiver*/, + uint16_t /*remote_delay_ms*/) { + inc_func_call_count(__func__); +} + +void HearingAidAudioSource::Stop() { inc_func_call_count(__func__); } + +void HearingAidAudioSource::Initialize() { inc_func_call_count(__func__); } + +void HearingAidAudioSource::CleanUp() { inc_func_call_count(__func__); } + +void HearingAidAudioSource::DebugDump(int /*fd*/) { inc_func_call_count(__func__); } diff --git a/system/test/mock/mock_main_shim_acl.cc b/system/test/mock/mock_main_shim_acl.cc index a98e809ad0..5f58860347 100644 --- a/system/test/mock/mock_main_shim_acl.cc +++ b/system/test/mock/mock_main_shim_acl.cc @@ -129,12 +129,6 @@ void shim::Acl::DisconnectLe(uint16_t /* handle */, tHCI_STATUS /* reason */, inc_func_call_count(__func__); } -void shim::Acl::LeSetDefaultSubrate(uint16_t /* subrate_min */, uint16_t /* subrate_max */, - uint16_t /* max_latency */, uint16_t /* cont_num */, - uint16_t /* sup_tout */) { - inc_func_call_count(__func__); -} - void shim::Acl::LeSubrateRequest(uint16_t /* hci_handle */, uint16_t /* subrate_min */, uint16_t /* subrate_max */, uint16_t /* max_latency */, uint16_t /* cont_num */, uint16_t /* sup_tout */) { diff --git a/system/test/mock/mock_main_shim_acl_api.cc b/system/test/mock/mock_main_shim_acl_api.cc index 3d257f1a5a..e3a3c9d63b 100644 --- a/system/test/mock/mock_main_shim_acl_api.cc +++ b/system/test/mock/mock_main_shim_acl_api.cc @@ -73,12 +73,6 @@ void bluetooth::shim::ACL_RemoveFromAddressResolution( inc_func_call_count(__func__); } void bluetooth::shim::ACL_ClearAddressResolution() { inc_func_call_count(__func__); } -void bluetooth::shim::ACL_LeSetDefaultSubrate(uint16_t /* subrate_min */, - uint16_t /* subrate_max */, - uint16_t /* max_latency */, uint16_t /* cont_num */, - uint16_t /* sup_tout */) { - inc_func_call_count(__func__); -} void bluetooth::shim::ACL_LeSubrateRequest(uint16_t /* hci_handle */, uint16_t /* subrate_min */, uint16_t /* subrate_max */, uint16_t /* max_latency */, uint16_t /* cont_num */, uint16_t /* sup_tout */) { diff --git a/system/test/mock/mock_main_shim_acl_api.h b/system/test/mock/mock_main_shim_acl_api.h index ab891673e3..29e27dbad3 100644 --- a/system/test/mock/mock_main_shim_acl_api.h +++ b/system/test/mock/mock_main_shim_acl_api.h @@ -84,21 +84,6 @@ struct ACL_ClearFilterAcceptList { }; extern struct ACL_ClearFilterAcceptList ACL_ClearFilterAcceptList; -// Name: ACL_LeSetDefaultSubrate -// Params: -// Return: void -struct ACL_LeSetDefaultSubrate { - std::function<void(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t sup_tout)> - body{[](uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t sup_tout) {}}; - void operator()(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, - uint16_t cont_num, uint16_t sup_tout) { - body(subrate_min, subrate_max, max_latency, cont_num, sup_tout); - } -}; -extern struct ACL_LeSetDefaultSubrate ACL_LeSetDefaultSubrate; - // Name: ACL_LeSubrateRequest // Params: // Return: void diff --git a/system/test/mock/mock_main_shim_entry.cc b/system/test/mock/mock_main_shim_entry.cc index 5d68f11b9d..3cdc714eaf 100644 --- a/system/test/mock/mock_main_shim_entry.cc +++ b/system/test/mock/mock_main_shim_entry.cc @@ -38,9 +38,9 @@ namespace bluetooth { namespace hci { namespace testing { -MockAclManager* mock_acl_manager_{nullptr}; -MockControllerInterface* mock_controller_{nullptr}; -HciInterface* mock_hci_layer_{nullptr}; +std::unique_ptr<MockAclManager> mock_acl_manager_; +std::unique_ptr<MockControllerInterface> mock_controller_; +std::unique_ptr<MockHciLayer> mock_hci_layer_; os::Handler* mock_gd_shim_handler_{nullptr}; MockLeAdvertisingManager* mock_le_advertising_manager_{nullptr}; MockLeScanningManager* mock_le_scanning_manager_{nullptr}; @@ -58,9 +58,9 @@ class Dumpsys; namespace shim { -hci::AclManager* GetAclManager() { return hci::testing::mock_acl_manager_; } -hci::ControllerInterface* GetController() { return hci::testing::mock_controller_; } -hci::HciInterface* GetHciLayer() { return hci::testing::mock_hci_layer_; } +hci::AclManager* GetAclManager() { return hci::testing::mock_acl_manager_.get(); } +hci::ControllerInterface* GetController() { return hci::testing::mock_controller_.get(); } +hci::HciInterface* GetHciLayer() { return hci::testing::mock_hci_layer_.get(); } hci::LeAdvertisingManager* GetAdvertising() { return hci::testing::mock_le_advertising_manager_; } hci::LeScanningManager* GetScanning() { return hci::testing::mock_le_scanning_manager_; } hci::DistanceMeasurementManager* GetDistanceMeasurementManager() { diff --git a/system/test/mock/mock_main_shim_entry.h b/system/test/mock/mock_main_shim_entry.h index ca84a27193..5d427fd963 100644 --- a/system/test/mock/mock_main_shim_entry.h +++ b/system/test/mock/mock_main_shim_entry.h @@ -15,11 +15,12 @@ */ #include <functional> +#include <memory> #include "hci/acl_manager_mock.h" #include "hci/controller_interface_mock.h" #include "hci/distance_measurement_manager_mock.h" -#include "hci/hci_interface.h" +#include "hci/hci_layer_mock.h" #include "hci/le_advertising_manager_mock.h" #include "hci/le_scanning_manager_mock.h" #include "storage/storage_module.h" @@ -28,9 +29,9 @@ namespace bluetooth { namespace hci { namespace testing { -extern MockAclManager* mock_acl_manager_; -extern MockControllerInterface* mock_controller_; -extern HciInterface* mock_hci_layer_; +extern std::unique_ptr<MockAclManager> mock_acl_manager_; +extern std::unique_ptr<MockControllerInterface> mock_controller_; +extern std::unique_ptr<MockHciLayer> mock_hci_layer_; extern os::Handler* mock_gd_shim_handler_; extern MockLeAdvertisingManager* mock_le_advertising_manager_; extern MockLeScanningManager* mock_le_scanning_manager_; diff --git a/system/test/mock/mock_stack_gap_conn.cc b/system/test/mock/mock_stack_gap_conn_interface.cc index 07193c9130..2ef1a3ef8f 100644 --- a/system/test/mock/mock_stack_gap_conn.cc +++ b/system/test/mock/mock_stack_gap_conn_interface.cc @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright 2025 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. @@ -14,19 +14,39 @@ * limitations under the License. */ -/* - * Generated mock file from original source file - * Functions generated:13 - */ +#include "test/mock/mock_stack_gap_conn_interface.h" -#include "gap_api.h" -#include "stack/include/bt_hdr.h" +#include "stack/include/gap_api.h" #include "test/common/mock_functions.h" -#include "types/raw_address.h" -const RawAddress* GAP_ConnGetRemoteAddr(uint16_t /* gap_handle */) { +namespace { +bluetooth::testing::stack::gap_conn::Mock mock_gap_conn_interface; +bluetooth::testing::stack::gap_conn::Interface* interface_ = &mock_gap_conn_interface; +} // namespace + +void bluetooth::testing::stack::gap_conn::reset_interface() { + interface_ = &mock_gap_conn_interface; +} + +void bluetooth::testing::stack::gap_conn::set_interface( + bluetooth::testing::stack::gap_conn::Interface* interface) { + interface_ = interface; +} + +uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id, bool is_server, + const RawAddress* p_rem_bda, uint16_t psm, uint16_t le_mps, + tL2CAP_CFG_INFO* p_cfg, tL2CAP_ERTM_INFO* ertm_info, uint16_t security, + tGAP_CONN_CALLBACK* p_cb, tBT_TRANSPORT transport) { inc_func_call_count(__func__); - return nullptr; + + return interface_->GAP_ConnOpen(p_serv_name, service_id, is_server, p_rem_bda, psm, le_mps, p_cfg, + ertm_info, security, p_cb, transport); +} + +const RawAddress* GAP_ConnGetRemoteAddr(uint16_t gap_handle) { + inc_func_call_count(__func__); + + return interface_->GAP_ConnGetRemoteAddr(gap_handle); } int GAP_GetRxQueueCnt(uint16_t /* handle */, uint32_t* /* p_rx_queue_count */) { inc_func_call_count(__func__); @@ -44,14 +64,6 @@ uint16_t GAP_ConnGetRemMtuSize(uint16_t /* gap_handle */) { inc_func_call_count(__func__); return 0; } -uint16_t GAP_ConnOpen(const char* /* p_serv_name */, uint8_t /* service_id */, bool /* is_server */, - const RawAddress* /* p_rem_bda */, uint16_t /* psm */, uint16_t /* le_mps */, - tL2CAP_CFG_INFO* /* p_cfg */, tL2CAP_ERTM_INFO* /* ertm_info */, - uint16_t /* security */, tGAP_CONN_CALLBACK* /* p_cb */, - tBT_TRANSPORT /* transport */) { - inc_func_call_count(__func__); - return 0; -} uint16_t GAP_ConnReadData(uint16_t /* gap_handle */, uint8_t* /* p_data */, uint16_t /* max_len */, uint16_t* /* p_len */) { inc_func_call_count(__func__); @@ -74,3 +86,8 @@ bool GAP_IsTransportLe(uint16_t /* gap_handle */) { return false; } void GAP_Init(void) { inc_func_call_count(__func__); } + +bluetooth::testing::stack::gap_conn::Interface& +bluetooth::testing::stack::gap_conn::get_interface() { + return *interface_; +} diff --git a/system/test/mock/mock_stack_gap_conn_interface.h b/system/test/mock/mock_stack_gap_conn_interface.h new file mode 100644 index 0000000000..c1ed7caea3 --- /dev/null +++ b/system/test/mock/mock_stack_gap_conn_interface.h @@ -0,0 +1,63 @@ +/* + * Copyright 2024 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 + +#include <gmock/gmock.h> + +#include <vector> + +#include "stack/include/gap_api.h" + +namespace bluetooth { +namespace testing { +namespace stack { +namespace gap_conn { + +class Interface { +public: + virtual ~Interface() = default; + + virtual uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id, bool is_server, + const RawAddress* p_rem_bda, uint16_t psm, uint16_t le_mps, + tL2CAP_CFG_INFO* p_cfg, tL2CAP_ERTM_INFO* ertm_info, + uint16_t security, tGAP_CONN_CALLBACK* p_cb, + tBT_TRANSPORT transport) = 0; + + virtual const RawAddress* GAP_ConnGetRemoteAddr(uint16_t gap_handle) = 0; +}; + +class Mock : public Interface { +public: + ~Mock() = default; + + MOCK_METHOD(uint16_t, GAP_ConnOpen, + (const char* p_serv_name, uint8_t service_id, bool is_server, + const RawAddress* p_rem_bda, uint16_t psm, uint16_t le_mps, tL2CAP_CFG_INFO* p_cfg, + tL2CAP_ERTM_INFO* ertm_info, uint16_t security, tGAP_CONN_CALLBACK* p_cb, + tBT_TRANSPORT transport)); + + MOCK_METHOD(const RawAddress*, GAP_ConnGetRemoteAddr, (uint16_t gap_handle)); +}; + +void reset_interface(); +void set_interface(Interface* interface_); +Interface& get_interface(); + +} // namespace gap_conn +} // namespace stack +} // namespace testing +} // namespace bluetooth diff --git a/system/test/mock/mock_stack_l2cap_interface.h b/system/test/mock/mock_stack_l2cap_interface.h index a5cd536777..b2fc3e0ae9 100644 --- a/system/test/mock/mock_stack_l2cap_interface.h +++ b/system/test/mock/mock_stack_l2cap_interface.h @@ -64,9 +64,6 @@ public: MOCK_METHOD(bool, L2CA_GetPeerFeatures, (const RawAddress& bd_addr, uint32_t* p_ext_feat, uint8_t* p_chnl_mask)); MOCK_METHOD(bool, L2CA_SetAclPriority, (const RawAddress& bd_addr, tL2CAP_PRIORITY priority)); - MOCK_METHOD(void, L2CA_SetDefaultSubrate, - (uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, - uint16_t timeout)); MOCK_METHOD(void, L2CA_AdjustConnectionIntervals, (uint16_t* min_interval, uint16_t* max_interval, uint16_t floor_interval)); MOCK_METHOD(void, L2CA_SetEcosystemBaseInterval, (uint32_t base_interval)); diff --git a/system/test/mock/mock_stack_metrics_logging.cc b/system/test/mock/mock_stack_metrics_logging.cc deleted file mode 100644 index ff2cee4472..0000000000 --- a/system/test/mock/mock_stack_metrics_logging.cc +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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:5 - * - * mockcify.pl ver 0.2 - */ -// Mock include file to share data between tests and mock -#include "test/mock/mock_stack_metrics_logging.h" - -#include <string> - -// Original included files, if any -#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h> -#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h> - -#include "stack/include/stack_metrics_logging.h" -#include "test/common/mock_functions.h" -#include "types/raw_address.h" - -// Mocked compile conditionals, if any -// Mocked internal structures, if any - -namespace test { -namespace mock { -namespace stack_metrics_logging { - -// Function state capture and return values, if needed -struct log_classic_pairing_event log_classic_pairing_event; -struct log_link_layer_connection_event log_link_layer_connection_event; -struct log_smp_pairing_event log_smp_pairing_event; -struct log_le_pairing_fail log_le_pairing_fail; -struct log_sdp_attribute log_sdp_attribute; -struct log_manufacturer_info log_manufacturer_info; -struct log_counter_metrics log_counter_metrics; -struct log_hfp_audio_packet_loss_stats log_hfp_audio_packet_loss_stats; -struct log_mmc_transcode_rtt_stats log_mmc_transcode_rtt_stats; -struct log_le_connection_status log_le_connection_status; -struct log_le_device_in_accept_list log_le_device_in_accept_list; -struct log_le_connection_lifecycle log_le_connection_lifecycle; -struct log_le_connection_completion log_le_connection_completion; - -} // namespace stack_metrics_logging -} // namespace mock -} // namespace test - -// Mocked functions, if any -void log_classic_pairing_event(const RawAddress& address, uint16_t handle, uint32_t hci_cmd, - uint16_t hci_event, uint16_t cmd_status, uint16_t reason_code, - int64_t event_value) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_classic_pairing_event( - address, handle, hci_cmd, hci_event, cmd_status, reason_code, event_value); -} -void log_link_layer_connection_event(const RawAddress* address, uint32_t connection_handle, - android::bluetooth::DirectionEnum direction, - uint16_t link_type, uint32_t hci_cmd, uint16_t hci_event, - uint16_t hci_ble_event, uint16_t cmd_status, - uint16_t reason_code) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_link_layer_connection_event( - address, connection_handle, direction, link_type, hci_cmd, hci_event, hci_ble_event, - cmd_status, reason_code); -} -void log_smp_pairing_event(const RawAddress& address, uint16_t smp_cmd, - android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_smp_pairing_event(address, smp_cmd, direction, - smp_fail_reason); -} - -void log_le_pairing_fail(const RawAddress& raw_address, uint8_t failure_reason, bool is_outgoing) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_le_pairing_fail(raw_address, failure_reason, is_outgoing); -} - -void log_sdp_attribute(const RawAddress& address, uint16_t protocol_uuid, uint16_t attribute_id, - size_t attribute_size, const char* attribute_value) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_sdp_attribute(address, protocol_uuid, attribute_id, - attribute_size, attribute_value); -} -void log_manufacturer_info(const RawAddress& address, - android::bluetooth::AddressTypeEnum address_type, - android::bluetooth::DeviceInfoSrcEnum source_type, - const std::string& source_name, const std::string& manufacturer, - const std::string& model, const std::string& hardware_version, - const std::string& software_version) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_manufacturer_info(address, address_type, source_type, - source_name, manufacturer, model, - hardware_version, software_version); -} - -void log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum key, int64_t value) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_counter_metrics(key, value); -} - -void log_hfp_audio_packet_loss_stats(const RawAddress& address, int num_decoded_frames, - double packet_loss_ratio, uint16_t codec_type) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_hfp_audio_packet_loss_stats(address, num_decoded_frames, - packet_loss_ratio, codec_type); -} - -void log_mmc_transcode_rtt_stats(int maximum_rtt, double mean_rtt, int num_requests, - int codec_type) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_mmc_transcode_rtt_stats(maximum_rtt, mean_rtt, - num_requests, codec_type); -} - -void log_le_connection_status(bluetooth::hci::Address address, bool is_connect, - bluetooth::hci::ErrorCode reason) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_le_connection_status(address, is_connect, reason); -} - -void log_le_device_in_accept_list(bluetooth::hci::Address address, bool is_add) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_le_device_in_accept_list(address, is_add); -} - -void log_le_connection_lifecycle(bluetooth::hci::Address address, bool is_connect, bool is_direct) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_le_connection_lifecycle(address, is_connect, is_direct); -} - -void log_le_connection_completion(bluetooth::hci::Address address, bluetooth::hci::ErrorCode reason, - bool is_locally_initiated) { - inc_func_call_count(__func__); - test::mock::stack_metrics_logging::log_le_connection_completion(address, reason, - is_locally_initiated); -} -// END mockcify generation diff --git a/system/test/mock/mock_stack_metrics_logging.h b/system/test/mock/mock_stack_metrics_logging.h deleted file mode 100644 index 40212e60ea..0000000000 --- a/system/test/mock/mock_stack_metrics_logging.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - * 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:5 - * - * mockcify.pl ver 0.2 - */ - -#include <string> - -// Original included files, if any -#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h> -#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h> - -#include "hci/address.h" -#include "hci/hci_packets.h" -#include "types/raw_address.h" - -// Mocked compile conditionals, if any - -namespace test { -namespace mock { -namespace stack_metrics_logging { - -// Shared state between mocked functions and tests -// Name: log_classic_pairing_event -// Params: const RawAddress& address, uint16_t handle, uint32_t hci_cmd, -// uint16_t hci_event, uint16_t cmd_status, uint16_t reason_code, int64_t -// event_value Returns: void -struct log_classic_pairing_event { - std::function<void(const RawAddress& address, uint16_t handle, uint32_t hci_cmd, - uint16_t hci_event, uint16_t cmd_status, uint16_t reason_code, - int64_t event_value)> - body{[](const RawAddress& /* address */, uint16_t /* handle */, uint32_t /* hci_cmd */, - uint16_t /* hci_event */, uint16_t /* cmd_status */, uint16_t /* reason_code */, - int64_t /* event_value */) {}}; - void operator()(const RawAddress& address, uint16_t handle, uint32_t hci_cmd, uint16_t hci_event, - uint16_t cmd_status, uint16_t reason_code, int64_t event_value) { - body(address, handle, hci_cmd, hci_event, cmd_status, reason_code, event_value); - } -}; -extern struct log_classic_pairing_event log_classic_pairing_event; -// Name: log_link_layer_connection_event -// Params: const RawAddress* address, uint32_t connection_handle, -// android::bluetooth::DirectionEnum direction, uint16_t link_type, uint32_t -// hci_cmd, uint16_t hci_event, uint16_t hci_ble_event, uint16_t cmd_status, -// uint16_t reason_code Returns: void -struct log_link_layer_connection_event { - std::function<void(const RawAddress* address, uint32_t connection_handle, - android::bluetooth::DirectionEnum direction, uint16_t link_type, - uint32_t hci_cmd, uint16_t hci_event, uint16_t hci_ble_event, - uint16_t cmd_status, uint16_t reason_code)> - body{[](const RawAddress* /* address */, uint32_t /* connection_handle */, - android::bluetooth::DirectionEnum /* direction */, uint16_t /* link_type */, - uint32_t /* hci_cmd */, uint16_t /* hci_event */, uint16_t /* hci_ble_event */, - uint16_t /* cmd_status */, uint16_t /* reason_code */) {}}; - void operator()(const RawAddress* address, uint32_t connection_handle, - android::bluetooth::DirectionEnum direction, uint16_t link_type, uint32_t hci_cmd, - uint16_t hci_event, uint16_t hci_ble_event, uint16_t cmd_status, - uint16_t reason_code) { - body(address, connection_handle, direction, link_type, hci_cmd, hci_event, hci_ble_event, - cmd_status, reason_code); - } -}; -extern struct log_link_layer_connection_event log_link_layer_connection_event; -// Name: log_smp_pairing_event -// Params: const RawAddress& address, uint16_t smp_cmd, -// android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason Returns: -// void -struct log_smp_pairing_event { - std::function<void(const RawAddress& address, uint16_t smp_cmd, - android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason)> - body{[](const RawAddress& /* address */, uint16_t /* smp_cmd */, - android::bluetooth::DirectionEnum /* direction */, - uint16_t /* smp_fail_reason */) {}}; - void operator()(const RawAddress& address, uint16_t smp_cmd, - android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) { - body(address, smp_cmd, direction, smp_fail_reason); - } -}; -extern struct log_smp_pairing_event log_smp_pairing_event; - -// Name: log_le_pairing_fail -// Params: const RawAddress& raw_address, uint8_t failure_reason, bool -// is_outgoing Returns: -// void -// Name: log_sdp_attribute -// Params: const RawAddress& address, uint16_t protocol_uuid, uint16_t -// attribute_id, size_t attribute_size, const char* attribute_value Returns: -// void -struct log_le_pairing_fail { - std::function<void(const RawAddress& raw_address, uint8_t failure_reason, bool is_outgoing)> body{ - [](const RawAddress& /* address */, uint8_t /* failure reason */, - bool /* is_outgoing */) {}}; - void operator()(const RawAddress& raw_address, uint8_t failure_reason, bool is_outgoing) { - body(raw_address, failure_reason, is_outgoing); - } -}; -extern struct log_le_pairing_fail log_le_pairing_fail; - -struct log_sdp_attribute { - std::function<void(const RawAddress& address, uint16_t protocol_uuid, uint16_t attribute_id, - size_t attribute_size, const char* attribute_value)> - body{[](const RawAddress& /* address */, uint16_t /* protocol_uuid */, - uint16_t /* attribute_id */, size_t /* attribute_size */, - const char* /* attribute_value */) {}}; - void operator()(const RawAddress& address, uint16_t protocol_uuid, uint16_t attribute_id, - size_t attribute_size, const char* attribute_value) { - body(address, protocol_uuid, attribute_id, attribute_size, attribute_value); - } -}; -extern struct log_sdp_attribute log_sdp_attribute; -// Name: log_manufacturer_info -// Params: const RawAddress& address, android::bluetooth::DeviceInfoSrcEnum -// source_type, const std::string& source_name, const std::string& manufacturer, -// const std::string& model, const std::string& hardware_version, const -// std::string& software_version Returns: void -struct log_manufacturer_info { - std::function<void(const RawAddress& address, android::bluetooth::AddressTypeEnum address_type, - android::bluetooth::DeviceInfoSrcEnum source_type, - const std::string& source_name, const std::string& manufacturer, - const std::string& model, const std::string& hardware_version, - const std::string& software_version)> - body2{[](const RawAddress& /* address */, - android::bluetooth::AddressTypeEnum /* address_type */, - android::bluetooth::DeviceInfoSrcEnum /* source_type */, - const std::string& /* source_name */, const std::string& /* manufacturer */, - const std::string& /* model */, const std::string& /* hardware_version */, - const std::string& /* software_version */) {}}; - void operator()(const RawAddress& address, android::bluetooth::AddressTypeEnum address_type, - android::bluetooth::DeviceInfoSrcEnum source_type, const std::string& source_name, - const std::string& manufacturer, const std::string& model, - const std::string& hardware_version, const std::string& software_version) { - body2(address, address_type, source_type, source_name, manufacturer, model, hardware_version, - software_version); - } - std::function<void(const RawAddress& address, android::bluetooth::DeviceInfoSrcEnum source_type, - const std::string& source_name, const std::string& manufacturer, - const std::string& model, const std::string& hardware_version, - const std::string& software_version)> - body{[](const RawAddress& /* address */, - android::bluetooth::DeviceInfoSrcEnum /* source_type */, - const std::string& /* source_name */, const std::string& /* manufacturer */, - const std::string& /* model */, const std::string& /* hardware_version */, - const std::string& /* software_version */) {}}; - void operator()(const RawAddress& address, android::bluetooth::DeviceInfoSrcEnum source_type, - const std::string& source_name, const std::string& manufacturer, - const std::string& model, const std::string& hardware_version, - const std::string& software_version) { - body(address, source_type, source_name, manufacturer, model, hardware_version, - software_version); - } -}; -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; - -// Name: log_hfp_audio_packet_loss_stats -struct log_hfp_audio_packet_loss_stats { - std::function<void(const RawAddress& address, int num_decoded_frames, double packet_loss_ratio, - uint16_t codec_type)> - body{[](const RawAddress& /* address */, int /* num_decoded_frames */, - double /* packet_loss_ratio */, uint16_t /* codec_type */) {}}; - void operator()(const RawAddress& address, int num_decoded_frames, double packet_loss_ratio, - uint16_t codec_type) { - body(address, num_decoded_frames, packet_loss_ratio, codec_type); - } -}; -extern struct log_hfp_audio_packet_loss_stats log_hfp_audio_packet_loss_stats; - -// Name: log_mmc_transcode_rtt_stats -struct log_mmc_transcode_rtt_stats { - std::function<void(int maximum_rtt, double mean_rtt, int num_requests, int codec_type)> body{ - [](int /* maximum_rtt */, double /* mean_rtt */, int /* num_requests */, - int /* codec_type */) {}}; - void operator()(int maximum_rtt, double mean_rtt, int num_requests, int codec_type) { - body(maximum_rtt, mean_rtt, num_requests, codec_type); - } -}; -extern struct log_mmc_transcode_rtt_stats log_mmc_transcode_rtt_stats; - -// Name: log_le_connection_status -struct log_le_connection_status { - std::function<void(bluetooth::hci::Address address, bool is_connect, - bluetooth::hci::ErrorCode reason)> - body{[](bluetooth::hci::Address /* address */, bool /* is_connect */, - bluetooth::hci::ErrorCode /* reason */) {}}; - void operator()(bluetooth::hci::Address address, bool is_connect, - bluetooth::hci::ErrorCode reason) { - body(address, is_connect, reason); - } -}; -extern struct log_le_connection_status log_le_connection_status; - -// Name: log_le_device_in_accept_list -struct log_le_device_in_accept_list { - std::function<void(bluetooth::hci::Address address, bool is_add)> body{ - [](bluetooth::hci::Address /* address */, bool /* is_add */) {}}; - void operator()(bluetooth::hci::Address address, bool is_add) { body(address, is_add); } -}; -extern struct log_le_device_in_accept_list log_le_device_in_accept_list; - -// Name: log_le_connection_lifecycle -struct log_le_connection_lifecycle { - std::function<void(bluetooth::hci::Address address, bool is_connect, bool is_direct)> body{ - [](bluetooth::hci::Address /* address */, bool /* is_connect */, bool /* is_direct */) { - }}; - void operator()(bluetooth::hci::Address address, bool is_connect, bool is_direct) { - body(address, is_connect, is_direct); - } -}; -extern struct log_le_device_in_accept_list log_le_device_in_accept_list; - -// Name: log_le_connection_completion -struct log_le_connection_completion { - std::function<void(bluetooth::hci::Address address, bluetooth::hci::ErrorCode reason, - bool is_locally_initiated)> - body{[](bluetooth::hci::Address /* address */, bluetooth::hci::ErrorCode /* reason */, - bool /* is locally initiated */) {}}; - void operator()(bluetooth::hci::Address address, bluetooth::hci::ErrorCode reason, - bool is_locally_initiated) { - body(address, reason, is_locally_initiated); - } -}; -extern struct log_le_connection_completion log_le_connection_completion; - -} // namespace stack_metrics_logging -} // namespace mock -} // namespace test - -// END mockcify generation diff --git a/system/test/suite/adapter/adapter_unittest.cc b/system/test/suite/adapter/adapter_unittest.cc index 8e2769ea10..e295cb473d 100644 --- a/system/test/suite/adapter/adapter_unittest.cc +++ b/system/test/suite/adapter/adapter_unittest.cc @@ -16,8 +16,11 @@ * ******************************************************************************/ +#include <bluetooth/log.h> + #include "adapter/bluetooth_test.h" -#include "btcore/include/property.h" +#include "osi/include/allocator.h" +#include "osi/include/compat.h" #include "types/bt_transport.h" #include "types/raw_address.h" @@ -58,6 +61,52 @@ TEST_F(BluetoothTest, AdapterRepeatedEnableDisable) { } } +static bt_property_t* property_new_name(const char* name) { + bluetooth::log::assert_that(name != NULL, "assert failed: name != NULL"); + bt_property_t* property = static_cast<bt_property_t*>(osi_calloc(sizeof(bt_property_t))); + + property->val = osi_calloc(sizeof(bt_bdname_t) + 1); + osi_strlcpy((char*)property->val, name, sizeof(bt_bdname_t)); + + property->type = BT_PROPERTY_BDNAME; + property->len = sizeof(bt_bdname_t); + + return property; +} + +static void property_free(bt_property_t* property) { + if (property == NULL) { + return; + } + + osi_free(property->val); + osi_free(property); +} + +static const bt_bdname_t* property_as_name(const bt_property_t* property) { + bluetooth::log::assert_that(property->type == BT_PROPERTY_BDNAME, + "assert failed: property_is_name(property)"); + return (const bt_bdname_t*)property->val; +} + +static bool property_equals(const bt_property_t* p1, const bt_property_t* p2) { + if (!p1 || !p2 || p1->type != p2->type) { + return false; + } + + if (p1->type == BT_PROPERTY_BDNAME && p1->len != p2->len) { + const bt_property_t *shorter = p1, *longer = p2; + if (p1->len > p2->len) { + shorter = p2; + longer = p1; + } + return strlen((const char*)longer->val) == (size_t)shorter->len && + !memcmp(longer->val, shorter->val, shorter->len); + } + + return p1->len == p2->len && !memcmp(p1->val, p2->val, p1->len); +} + TEST_F(BluetoothTest, AdapterSetGetName) { bt_property_t* new_name = property_new_name("BluetoothTestName1"); diff --git a/system/test/suite/adapter/bluetooth_test.cc b/system/test/suite/adapter/bluetooth_test.cc index 4855b7a72d..490675a9f6 100644 --- a/system/test/suite/adapter/bluetooth_test.cc +++ b/system/test/suite/adapter/bluetooth_test.cc @@ -19,10 +19,11 @@ #include "adapter/bluetooth_test.h" #include <binder/ProcessState.h> +#include <bluetooth/log.h> #include <mutex> -#include "btcore/include/property.h" +#include "osi/include/allocator.h" #include "types/raw_address.h" extern bt_interface_t bluetoothInterface; @@ -35,6 +36,31 @@ namespace bttest { static BluetoothTest* instance = nullptr; +static void property_free_array(bt_property_t* properties, size_t count) { + if (properties == NULL) { + return; + } + + for (size_t i = 0; i < count; ++i) { + osi_free(properties[i].val); + } + + osi_free(properties); +} + +static bt_property_t* property_copy_array(const bt_property_t* properties, size_t count) { + bluetooth::log::assert_that(properties != NULL, "assert failed: properties != NULL"); + bt_property_t* clone = static_cast<bt_property_t*>(osi_calloc(sizeof(bt_property_t) * count)); + + memcpy(&clone[0], &properties[0], sizeof(bt_property_t) * count); + for (size_t i = 0; i < count; ++i) { + clone[i].val = osi_calloc(clone[i].len); + memcpy(clone[i].val, properties[i].val, clone[i].len); + } + + return clone; +} + void AdapterStateChangedCallback(bt_state_t new_state) { instance->state_ = new_state; semaphore_post(instance->adapter_state_changed_callback_sem_); diff --git a/tools/OWNERS b/tools/OWNERS deleted file mode 100644 index b2869ce1bc..0000000000 --- a/tools/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -# Reviewers for /tools - -jpawlowski@google.com -siyuanh@google.com -wescande@google.com diff --git a/tools/lint/OWNERS b/tools/lint/OWNERS deleted file mode 100644 index 9dd2d58fe3..0000000000 --- a/tools/lint/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# Additional OWNERS for Bluetooth AndroidLint -salsavage@google.com diff --git a/tools/rootcanal/OWNERS b/tools/rootcanal/OWNERS deleted file mode 100644 index 22b124fd96..0000000000 --- a/tools/rootcanal/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# Reviewers for /tools/rootcanal - -henrichataing@google.com |