diff options
21 files changed, 517 insertions, 38 deletions
diff --git a/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl b/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl index 00850fb6cd..4d72cfb6b3 100644 --- a/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl +++ b/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl @@ -153,7 +153,7 @@ interface IBluetoothGatt { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") void unregisterServer(in int serverIf, in AttributionSource attributionSource); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") - void serverConnect(in int serverIf, in String address, in boolean isDirect, in int transport, in AttributionSource attributionSource); + void serverConnect(in int serverIf, in String address, in int addressType, in boolean isDirect, in int transport, in AttributionSource attributionSource); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") void serverDisconnect(in int serverIf, in String address, in AttributionSource attributionSource); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)") diff --git a/android/app/jni/com_android_bluetooth_gatt.cpp b/android/app/jni/com_android_bluetooth_gatt.cpp index a33028532c..690277fb1c 100644 --- a/android/app/jni/com_android_bluetooth_gatt.cpp +++ b/android/app/jni/com_android_bluetooth_gatt.cpp @@ -1935,11 +1935,12 @@ static void gattServerUnregisterAppNative(JNIEnv* /* env */, static void gattServerConnectNative(JNIEnv* env, jobject /* object */, jint server_if, jstring address, - jboolean is_direct, jint transport) { + jint addr_type, jboolean is_direct, + jint transport) { if (!sGattIf) return; RawAddress bd_addr = str2addr(env, address); - sGattIf->server->connect(server_if, bd_addr, is_direct, transport); + sGattIf->server->connect(server_if, bd_addr, addr_type, is_direct, transport); } static void gattServerDisconnectNative(JNIEnv* env, jobject /* object */, @@ -2823,7 +2824,7 @@ static int register_com_android_bluetooth_gatt_(JNIEnv* env) { (void*)gattServerRegisterAppNative}, {"gattServerUnregisterAppNative", "(I)V", (void*)gattServerUnregisterAppNative}, - {"gattServerConnectNative", "(ILjava/lang/String;ZI)V", + {"gattServerConnectNative", "(ILjava/lang/String;IZI)V", (void*)gattServerConnectNative}, {"gattServerDisconnectNative", "(ILjava/lang/String;I)V", (void*)gattServerDisconnectNative}, diff --git a/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java b/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java index b119575844..4531b49a1a 100644 --- a/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java +++ b/android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java @@ -304,8 +304,10 @@ public class GattNativeInterface { private native void gattServerRegisterAppNative(long appUuidLsb, long appUuidMsb, boolean eattSupport); private native void gattServerUnregisterAppNative(int serverIf); - private native void gattServerConnectNative(int serverIf, String address, boolean isDirect, - int transport); + + private native void gattServerConnectNative( + int serverIf, String address, int addressType, boolean isDirect, int transport); + private native void gattServerDisconnectNative(int serverIf, String address, int connId); private native void gattServerSetPreferredPhyNative(int clientIf, String address, int txPhy, int rxPhy, int phyOptions); @@ -533,12 +535,10 @@ public class GattNativeInterface { gattServerUnregisterAppNative(serverIf); } - /** - * Connect to a remote device as a GATT server role - */ - public void gattServerConnect(int serverIf, String address, boolean isDirect, - int transport) { - gattServerConnectNative(serverIf, address, isDirect, transport); + /** Connect to a remote device as a GATT server role */ + public void gattServerConnect( + int serverIf, String address, int addressType, boolean isDirect, int transport) { + gattServerConnectNative(serverIf, address, addressType, isDirect, transport); } /** diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java index 636fa3ea58..82230a6b20 100644 --- a/android/app/src/com/android/bluetooth/gatt/GattService.java +++ b/android/app/src/com/android/bluetooth/gatt/GattService.java @@ -786,13 +786,19 @@ public class GattService extends ProfileService { } @Override - public void serverConnect(int serverIf, String address, boolean isDirect, int transport, + public void serverConnect( + int serverIf, + String address, + int addressType, + boolean isDirect, + int transport, AttributionSource attributionSource) { GattService service = getService(); if (service == null) { return; } - service.serverConnect(serverIf, address, isDirect, transport, attributionSource); + service.serverConnect( + serverIf, address, addressType, isDirect, transport, attributionSource); } @Override @@ -2676,7 +2682,12 @@ public class GattService extends ProfileService { } @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - void serverConnect(int serverIf, String address, boolean isDirect, int transport, + void serverConnect( + int serverIf, + String address, + int addressType, + boolean isDirect, + int transport, AttributionSource attributionSource) { if (!Utils.checkConnectPermissionForDataDelivery( this, attributionSource, "GattService serverConnect")) { @@ -2687,7 +2698,7 @@ public class GattService extends ProfileService { logServerForegroundInfo(attributionSource.getUid(), isDirect); - mNativeInterface.gattServerConnect(serverIf, address, isDirect, transport); + mNativeInterface.gattServerConnect(serverIf, address, addressType, isDirect, transport); } @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 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 4b0577579f..218dce7bc9 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 @@ -473,12 +473,16 @@ public class GattServiceBinderTest { public void serverConnect() { int serverIf = 1; String address = REMOTE_DEVICE_ADDRESS; + int addressType = BluetoothDevice.ADDRESS_TYPE_RANDOM; boolean isDirect = true; int transport = 2; - mBinder.serverConnect(serverIf, address, isDirect, transport, mAttributionSource); + mBinder.serverConnect( + serverIf, address, addressType, isDirect, transport, mAttributionSource); - verify(mService).serverConnect(serverIf, address, isDirect, transport, mAttributionSource); + verify(mService) + .serverConnect( + serverIf, address, addressType, isDirect, transport, mAttributionSource); } @Test 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 9440727b22..868d0501d3 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 @@ -511,11 +511,14 @@ public class GattServiceTest { public void serverConnect() { int serverIf = 1; String address = REMOTE_DEVICE_ADDRESS; + int addressType = BluetoothDevice.ADDRESS_TYPE_RANDOM; boolean isDirect = true; int transport = 2; - mService.serverConnect(serverIf, address, isDirect, transport, mAttributionSource); - verify(mNativeInterface).gattServerConnect(serverIf, address, isDirect, transport); + mService.serverConnect( + serverIf, address, addressType, isDirect, transport, mAttributionSource); + verify(mNativeInterface) + .gattServerConnect(serverIf, address, addressType, isDirect, transport); } @Test diff --git a/framework/java/android/bluetooth/BluetoothGattServer.java b/framework/java/android/bluetooth/BluetoothGattServer.java index 316f1d08a8..9dd195b5a1 100644 --- a/framework/java/android/bluetooth/BluetoothGattServer.java +++ b/framework/java/android/bluetooth/BluetoothGattServer.java @@ -721,7 +721,12 @@ public final class BluetoothGattServer implements BluetoothProfile { try { // autoConnect is inverse of "isDirect" mService.serverConnect( - mServerIf, device.getAddress(), !autoConnect, mTransport, mAttributionSource); + mServerIf, + device.getAddress(), + device.getAddressType(), + !autoConnect, + mTransport, + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); return false; diff --git a/framework/tests/bumble/AndroidManifest.xml b/framework/tests/bumble/AndroidManifest.xml index 2eb1e39a0f..83e44ed2a2 100644 --- a/framework/tests/bumble/AndroidManifest.xml +++ b/framework/tests/bumble/AndroidManifest.xml @@ -4,6 +4,8 @@ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.BLUETOOTH" /> + <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" /> diff --git a/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithScanTest.java b/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithScanTest.java new file mode 100644 index 0000000000..76e11c749b --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithScanTest.java @@ -0,0 +1,219 @@ +/* + * Copyright (C) 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. + */ + +package android.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; + +import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanCallback; +import android.bluetooth.le.ScanFilter; +import android.bluetooth.le.ScanResult; +import android.bluetooth.le.ScanSettings; +import android.content.Context; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.util.Log; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.runner.AndroidJUnit4; + +import com.android.bluetooth.flags.Flags; +import com.android.compatibility.common.util.AdoptShellPermissionsRule; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import pandora.HostProto.AdvertiseRequest; +import pandora.HostProto.OwnAddressType; + +/** Test cases for {@link BluetoothGattServer}. */ +@RunWith(AndroidJUnit4.class) +public class GattServerConnectWithScanTest { + private static final String TAG = "GattServerConnectWithScanTest"; + + private static final int TIMEOUT_SCANNING_MS = 2_000; + private static final int TIMEOUT_GATT_CONNECTION_MS = 2_000; + + @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); + + @Rule public final PandoraDevice mBumble = new PandoraDevice(); + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private final BluetoothManager mBluetoothManager = + mContext.getSystemService(BluetoothManager.class); + private final BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter(); + private final BluetoothLeScanner mLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); + + @Test + public void serverConnectToRandomAddress_withTransportAuto() throws Exception { + advertiseWithBumble(OwnAddressType.RANDOM); + assertThat(scanBumbleDevice(Utils.BUMBLE_RANDOM_ADDRESS)).isNotNull(); + + BluetoothGattServerCallback mockGattServerCallback = + mock(BluetoothGattServerCallback.class); + BluetoothGattServer gattServer = + mBluetoothManager.openGattServer( + mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_AUTO); + + assertThat(gattServer).isNotNull(); + + try { + BluetoothDevice device = + mBluetoothAdapter.getRemoteLeDevice( + Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); + + gattServer.connect(device, false); + verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + } finally { + gattServer.close(); + } + } + + @Test + public void serverConnectToRandomAddress_withTransportLE() throws Exception { + advertiseWithBumble(OwnAddressType.RANDOM); + assertThat(scanBumbleDevice(Utils.BUMBLE_RANDOM_ADDRESS)).isNotNull(); + + BluetoothGattServerCallback mockGattServerCallback = + mock(BluetoothGattServerCallback.class); + BluetoothGattServer gattServer = + mBluetoothManager.openGattServer( + mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_LE); + + assertThat(gattServer).isNotNull(); + + try { + BluetoothDevice device = + mBluetoothAdapter.getRemoteLeDevice( + Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); + + gattServer.connect(device, false); + verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + } finally { + gattServer.close(); + } + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_BLE_GATT_SERVER_USE_ADDRESS_TYPE_IN_CONNECTION) + public void serverConnectToPublicAddress_withTransportAuto() throws Exception { + String publicAddress = mBumble.getRemoteDevice().getAddress(); + advertiseWithBumble(OwnAddressType.PUBLIC); + assertThat(scanBumbleDevice(publicAddress)).isNotNull(); + + BluetoothGattServerCallback mockGattServerCallback = + mock(BluetoothGattServerCallback.class); + BluetoothGattServer gattServer = + mBluetoothManager.openGattServer( + mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_AUTO); + + assertThat(gattServer).isNotNull(); + + try { + gattServer.connect(mBumble.getRemoteDevice(), false); + verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + } finally { + gattServer.close(); + } + } + + @Test + public void serverConnectToPublicAddress_withTransportLE() throws Exception { + String publicAddress = mBumble.getRemoteDevice().getAddress(); + advertiseWithBumble(OwnAddressType.PUBLIC); + assertThat(scanBumbleDevice(publicAddress)).isNotNull(); + + BluetoothGattServerCallback mockGattServerCallback = + mock(BluetoothGattServerCallback.class); + BluetoothGattServer gattServer = + mBluetoothManager.openGattServer( + mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_LE); + + assertThat(gattServer).isNotNull(); + + try { + gattServer.connect(mBumble.getRemoteDevice(), false); + verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + } finally { + gattServer.close(); + } + } + + private void advertiseWithBumble(OwnAddressType ownAddressType) { + AdvertiseRequest request = + AdvertiseRequest.newBuilder() + .setLegacy(true) + .setConnectable(true) + .setOwnAddressType(ownAddressType) + .build(); + mBumble.hostBlocking().advertise(request); + } + + private List<ScanResult> scanBumbleDevice(String address) { + CompletableFuture<List<ScanResult>> future = new CompletableFuture<>(); + ScanSettings scanSettings = + new ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) + .build(); + + ScanFilter scanFilter = new ScanFilter.Builder().setDeviceAddress(address).build(); + + ScanCallback scanCallback = + new ScanCallback() { + @Override + public void onScanResult(int callbackType, ScanResult result) { + Log.d(TAG, "onScanResult: result=" + result); + future.complete(List.of(result)); + } + + @Override + public void onScanFailed(int errorCode) { + Log.d(TAG, "onScanFailed: errorCode=" + errorCode); + future.complete(null); + } + }; + + mLeScanner.startScan(List.of(scanFilter), scanSettings, scanCallback); + + List<ScanResult> result = + future.completeOnTimeout(null, TIMEOUT_SCANNING_MS, TimeUnit.MILLISECONDS).join(); + + mLeScanner.stopScan(scanCallback); + return result; + } +} diff --git a/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithoutScanTest.java b/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithoutScanTest.java new file mode 100644 index 0000000000..a7d83dda48 --- /dev/null +++ b/framework/tests/bumble/src/android/bluetooth/GattServerConnectWithoutScanTest.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 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. + */ + +package android.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.runner.AndroidJUnit4; + +import com.android.bluetooth.flags.Flags; +import com.android.compatibility.common.util.AdoptShellPermissionsRule; + +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import pandora.HostProto.AdvertiseRequest; +import pandora.HostProto.OwnAddressType; + +/** Test cases for {@link BluetoothGattServer}. */ +@RunWith(AndroidJUnit4.class) +public class GattServerConnectWithoutScanTest { + private static final String TAG = "GattServerConnectWithoutScanTest"; + private static final int TIMEOUT_GATT_CONNECTION_MS = 2_000; + + @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); + + @Rule public final PandoraDevice mBumble = new PandoraDevice(); + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private final BluetoothManager mBluetoothManager = + mContext.getSystemService(BluetoothManager.class); + private final BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter(); + + @Test + @RequiresFlagsEnabled(Flags.FLAG_BLE_GATT_SERVER_USE_ADDRESS_TYPE_IN_CONNECTION) + public void serverConnectToRandomAddress_withTransportAuto() throws Exception { + advertiseWithBumble(OwnAddressType.RANDOM); + + BluetoothGattServerCallback mockGattServerCallback = + mock(BluetoothGattServerCallback.class); + BluetoothGattServer gattServer = + mBluetoothManager.openGattServer( + mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_AUTO); + + assertThat(gattServer).isNotNull(); + + try { + BluetoothDevice device = + mBluetoothAdapter.getRemoteLeDevice( + Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); + + gattServer.connect(device, false); + verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + } finally { + gattServer.close(); + } + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_BLE_GATT_SERVER_USE_ADDRESS_TYPE_IN_CONNECTION) + public void serverConnectToRandomAddress_withTransportLE() throws Exception { + advertiseWithBumble(OwnAddressType.RANDOM); + + BluetoothGattServerCallback mockGattServerCallback = + mock(BluetoothGattServerCallback.class); + BluetoothGattServer gattServer = + mBluetoothManager.openGattServer( + mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_LE); + + assertThat(gattServer).isNotNull(); + + try { + BluetoothDevice device = + mBluetoothAdapter.getRemoteLeDevice( + Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); + + gattServer.connect(device, false); + verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + } finally { + gattServer.close(); + } + } + + @Test + @Ignore("b/333018293") + public void serverConnectToPublicAddress_withTransportAuto() throws Exception { + advertiseWithBumble(OwnAddressType.PUBLIC); + + BluetoothGattServerCallback mockGattServerCallback = + mock(BluetoothGattServerCallback.class); + BluetoothGattServer gattServer = + mBluetoothManager.openGattServer( + mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_AUTO); + + assertThat(gattServer).isNotNull(); + + try { + gattServer.connect(mBumble.getRemoteDevice(), false); + verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + } finally { + gattServer.close(); + } + } + + @Test + public void serverConnectToPublicAddress_withTransportLE() throws Exception { + advertiseWithBumble(OwnAddressType.PUBLIC); + + BluetoothGattServerCallback mockGattServerCallback = + mock(BluetoothGattServerCallback.class); + BluetoothGattServer gattServer = + mBluetoothManager.openGattServer( + mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_LE); + + assertThat(gattServer).isNotNull(); + + try { + gattServer.connect(mBumble.getRemoteDevice(), false); + verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS)) + .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED)); + } finally { + gattServer.close(); + } + } + + private void advertiseWithBumble(OwnAddressType ownAddressType) { + AdvertiseRequest request = + AdvertiseRequest.newBuilder() + .setLegacy(true) + .setConnectable(true) + .setOwnAddressType(ownAddressType) + .build(); + mBumble.hostBlocking().advertise(request); + } +} diff --git a/system/bta/gatt/bta_gatts_act.cc b/system/bta/gatt/bta_gatts_act.cc index cf2887ba50..0068a2f5de 100644 --- a/system/bta/gatt/bta_gatts_act.cc +++ b/system/bta/gatt/bta_gatts_act.cc @@ -23,6 +23,7 @@ * ******************************************************************************/ +#include <android_bluetooth_flags.h> #include <bluetooth/log.h> #include <cstdint> @@ -426,11 +427,20 @@ void bta_gatts_open(tBTA_GATTS_CB* /* p_cb */, tBTA_GATTS_DATA* p_msg) { p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_open.server_if); if (p_rcb != NULL) { /* should always get the connection ID */ - if (GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda, - p_msg->api_open.connection_type, p_msg->api_open.transport, - false)) { - status = GATT_SUCCESS; + bool success = false; + if (IS_FLAG_ENABLED(ble_gatt_server_use_address_type_in_connection)) { + success = GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda, + p_msg->api_open.remote_addr_type, + p_msg->api_open.connection_type, + p_msg->api_open.transport, false); + } else { + success = GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda, + p_msg->api_open.connection_type, + p_msg->api_open.transport, false); + } + if (success) { + status = GATT_SUCCESS; if (GATT_GetConnIdIfConnected(p_rcb->gatt_if, p_msg->api_open.remote_bda, &conn_id, p_msg->api_open.transport)) { status = GATT_ALREADY_OPEN; diff --git a/system/bta/gatt/bta_gatts_api.cc b/system/bta/gatt/bta_gatts_api.cc index 2c695919fb..fbcb67aea4 100644 --- a/system/bta/gatt/bta_gatts_api.cc +++ b/system/bta/gatt/bta_gatts_api.cc @@ -313,7 +313,8 @@ void BTA_GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id, tGATT_STATUS status, * ******************************************************************************/ void BTA_GATTS_Open(tGATT_IF server_if, const RawAddress& remote_bda, - bool is_direct, tBT_TRANSPORT transport) { + tBLE_ADDR_TYPE addr_type, bool is_direct, + tBT_TRANSPORT transport) { tBTA_GATTS_API_OPEN* p_buf = (tBTA_GATTS_API_OPEN*)osi_malloc(sizeof(tBTA_GATTS_API_OPEN)); @@ -326,6 +327,7 @@ void BTA_GATTS_Open(tGATT_IF server_if, const RawAddress& remote_bda, } p_buf->transport = transport; p_buf->remote_bda = remote_bda; + p_buf->remote_addr_type = addr_type; bta_sys_sendmsg(p_buf); } diff --git a/system/bta/gatt/bta_gatts_int.h b/system/bta/gatt/bta_gatts_int.h index a26fdb695e..578f9c6236 100644 --- a/system/bta/gatt/bta_gatts_int.h +++ b/system/bta/gatt/bta_gatts_int.h @@ -111,6 +111,7 @@ typedef struct { tGATT_IF server_if; tBTM_BLE_CONN_TYPE connection_type; tBT_TRANSPORT transport; + tBT_DEVICE_TYPE remote_addr_type; } tBTA_GATTS_API_OPEN; typedef struct { diff --git a/system/bta/include/bta_gatt_api.h b/system/bta/include/bta_gatt_api.h index 53b2d02101..981f7b4d3b 100644 --- a/system/bta/include/bta_gatt_api.h +++ b/system/bta/include/bta_gatt_api.h @@ -1017,13 +1017,16 @@ void BTA_GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id, tGATT_STATUS status, * * Parameters server_if: server interface. * remote_bda: remote device BD address. + * addr_type: remote device address type * is_direct: direct connection or background auto connection + * transport: transport to use in this connection * * Returns void * ******************************************************************************/ void BTA_GATTS_Open(tGATT_IF server_if, const RawAddress& remote_bda, - bool is_direct, tBT_TRANSPORT transport); + tBLE_ADDR_TYPE addr_type, bool is_direct, + tBT_TRANSPORT transport); /******************************************************************************* * diff --git a/system/btif/src/btif_gatt_server.cc b/system/btif/src/btif_gatt_server.cc index 8b5fe9d016..f45a681585 100644 --- a/system/btif/src/btif_gatt_server.cc +++ b/system/btif/src/btif_gatt_server.cc @@ -26,6 +26,7 @@ #define LOG_TAG "bt_btif_gatt" +#include <android_bluetooth_flags.h> #include <base/functional/bind.h> #include <bluetooth/log.h> #include <hardware/bluetooth.h> @@ -313,23 +314,55 @@ static void btif_gatts_open_impl(int server_if, const RawAddress& address, break; case BT_DEVICE_TYPE_DUMO: - if (transport_param == BT_TRANSPORT_LE) - transport = BT_TRANSPORT_LE; - else - transport = BT_TRANSPORT_BR_EDR; + transport = BT_TRANSPORT_BR_EDR; break; } } // Connect! - BTA_GATTS_Open(server_if, address, is_direct, transport); + BTA_GATTS_Open(server_if, address, BLE_ADDR_PUBLIC, is_direct, transport); +} + +// Used instead of btif_gatts_open_impl if the flag +// ble_gatt_server_use_address_type_in_connection is enabled. +static void btif_gatts_open_impl_use_address_type(int server_if, + const RawAddress& address, + tBLE_ADDR_TYPE addr_type, + bool is_direct, + int transport_param) { + int device_type = BT_DEVICE_TYPE_UNKNOWN; + if (btif_get_address_type(address, &addr_type) && + btif_get_device_type(address, &device_type) && + device_type != BT_DEVICE_TYPE_BREDR) { + BTA_DmAddBleDevice(address, addr_type, device_type); + } + + if (transport_param != BT_TRANSPORT_AUTO) { + log::info("addr_type:{}, transport_param:{}", addr_type, transport_param); + BTA_GATTS_Open(server_if, address, addr_type, is_direct, transport_param); + return; + } + + tBT_TRANSPORT transport = (device_type == BT_DEVICE_TYPE_BREDR) + ? BT_TRANSPORT_BR_EDR + : BT_TRANSPORT_LE; + log::info("addr_type:{}, transport:{}", addr_type, transport); + BTA_GATTS_Open(server_if, address, addr_type, is_direct, transport); } static bt_status_t btif_gatts_open(int server_if, const RawAddress& bd_addr, - bool is_direct, int transport) { + uint8_t addr_type, bool is_direct, + int transport) { CHECK_BTGATT_INIT(); - return do_in_jni_thread( - Bind(&btif_gatts_open_impl, server_if, bd_addr, is_direct, transport)); + + if (IS_FLAG_ENABLED(ble_gatt_server_use_address_type_in_connection)) { + return do_in_jni_thread(Bind(&btif_gatts_open_impl_use_address_type, + server_if, bd_addr, addr_type, is_direct, + transport)); + } else { + return do_in_jni_thread( + Bind(&btif_gatts_open_impl, server_if, bd_addr, is_direct, transport)); + } } static void btif_gatts_close_impl(int server_if, const RawAddress& address, diff --git a/system/gd/rust/linux/stack/src/bluetooth_gatt.rs b/system/gd/rust/linux/stack/src/bluetooth_gatt.rs index 8c95fde88d..4bcf47f6b4 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_gatt.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_gatt.rs @@ -2775,6 +2775,8 @@ impl IBluetoothGatt for BluetoothGatt { self.gatt.as_ref().unwrap().lock().unwrap().server.connect( server_id, &address, + // Addr type is default PUBLIC. + 0, is_direct, transport.into(), ); diff --git a/system/gd/rust/topshim/src/profiles/gatt.rs b/system/gd/rust/topshim/src/profiles/gatt.rs index d5c07de453..7f2f46d550 100644 --- a/system/gd/rust/topshim/src/profiles/gatt.rs +++ b/system/gd/rust/topshim/src/profiles/gatt.rs @@ -1406,10 +1406,11 @@ impl GattServer { &self, server_if: i32, addr: &RawAddress, + addr_type: u8, is_direct: bool, transport: i32, ) -> BtStatus { - BtStatus::from(ccall!(self, connect, server_if, addr, is_direct, transport)) + BtStatus::from(ccall!(self, connect, server_if, addr, addr_type, is_direct, transport)) } pub fn disconnect(&self, server_if: i32, addr: &RawAddress, conn_id: i32) -> BtStatus { diff --git a/system/include/hardware/bt_gatt_server.h b/system/include/hardware/bt_gatt_server.h index f80b2b9ae6..29f4f45055 100644 --- a/system/include/hardware/bt_gatt_server.h +++ b/system/include/hardware/bt_gatt_server.h @@ -154,7 +154,7 @@ typedef struct { /** Create a connection to a remote peripheral */ bt_status_t (*connect)(int server_if, const RawAddress& bd_addr, - bool is_direct, int transport); + uint8_t addr_type, bool is_direct, int transport); /** Disconnect an established connection or cancel a pending one */ bt_status_t (*disconnect)(int server_if, const RawAddress& bd_addr, diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc index f17afab4aa..4dd8933313 100644 --- a/system/stack/gatt/gatt_api.cc +++ b/system/stack/gatt/gatt_api.cc @@ -1501,6 +1501,15 @@ bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, } bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, + tBLE_ADDR_TYPE addr_type, tBTM_BLE_CONN_TYPE connection_type, + tBT_TRANSPORT transport, bool opportunistic) { + constexpr uint8_t kPhyLe1M = 0x01; // From the old controller shim. + uint8_t phy = kPhyLe1M; + return GATT_Connect(gatt_if, bd_addr, addr_type, connection_type, transport, + opportunistic, phy); +} + +bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, tBTM_BLE_CONN_TYPE connection_type, tBT_TRANSPORT transport, bool opportunistic, uint8_t initiating_phys) { return GATT_Connect(gatt_if, bd_addr, BLE_ADDR_PUBLIC, connection_type, diff --git a/system/stack/include/gatt_api.h b/system/stack/include/gatt_api.h index 3f88417ac2..f5778ed727 100644 --- a/system/stack/include/gatt_api.h +++ b/system/stack/include/gatt_api.h @@ -1192,6 +1192,9 @@ bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool opportunistic, uint8_t initiating_phys); bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, tBTM_BLE_CONN_TYPE connection_type, + tBT_TRANSPORT transport, bool opportunistic); +bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, + tBLE_ADDR_TYPE addr_type, tBTM_BLE_CONN_TYPE connection_type, tBT_TRANSPORT transport, bool opportunistic, uint8_t initiating_phys); diff --git a/system/test/mock/mock_bta_gatts_api.cc b/system/test/mock/mock_bta_gatts_api.cc index eba8de3a14..85175b1c53 100644 --- a/system/test/mock/mock_bta_gatts_api.cc +++ b/system/test/mock/mock_bta_gatts_api.cc @@ -62,7 +62,8 @@ void BTA_GATTS_HandleValueIndication(uint16_t /* conn_id */, inc_func_call_count(__func__); } void BTA_GATTS_Open(tGATT_IF /* server_if */, - const RawAddress& /* remote_bda */, bool /* is_direct */, + const RawAddress& /* remote_bda */, + tBLE_ADDR_TYPE /* addr_type */, bool /* is_direct */, tBT_TRANSPORT /* transport */) { inc_func_call_count(__func__); } |