summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/app/aidl/android/bluetooth/IBluetoothGatt.aidl2
-rw-r--r--android/app/jni/com_android_bluetooth_gatt.cpp7
-rw-r--r--android/app/src/com/android/bluetooth/gatt/GattNativeInterface.java16
-rw-r--r--android/app/src/com/android/bluetooth/gatt/GattService.java19
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java8
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java7
-rw-r--r--framework/java/android/bluetooth/BluetoothGattServer.java7
-rw-r--r--framework/tests/bumble/AndroidManifest.xml2
-rw-r--r--framework/tests/bumble/src/android/bluetooth/GattServerConnectWithScanTest.java219
-rw-r--r--framework/tests/bumble/src/android/bluetooth/GattServerConnectWithoutScanTest.java169
-rw-r--r--system/bta/gatt/bta_gatts_act.cc18
-rw-r--r--system/bta/gatt/bta_gatts_api.cc4
-rw-r--r--system/bta/gatt/bta_gatts_int.h1
-rw-r--r--system/bta/include/bta_gatt_api.h5
-rw-r--r--system/btif/src/btif_gatt_server.cc49
-rw-r--r--system/gd/rust/linux/stack/src/bluetooth_gatt.rs2
-rw-r--r--system/gd/rust/topshim/src/profiles/gatt.rs3
-rw-r--r--system/include/hardware/bt_gatt_server.h2
-rw-r--r--system/stack/gatt/gatt_api.cc9
-rw-r--r--system/stack/include/gatt_api.h3
-rw-r--r--system/test/mock/mock_bta_gatts_api.cc3
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__);
}