1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.bluetooth; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import android.bluetooth.le.AdvertiseData; 22 import android.bluetooth.le.AdvertisingSet; 23 import android.bluetooth.le.AdvertisingSetCallback; 24 import android.bluetooth.le.AdvertisingSetParameters; 25 import android.bluetooth.le.BluetoothLeAdvertiser; 26 import android.os.ParcelUuid; 27 import android.platform.test.annotations.RequiresFlagsEnabled; 28 import android.platform.test.flag.junit.CheckFlagsRule; 29 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 30 31 import androidx.test.ext.junit.runners.AndroidJUnit4; 32 33 import com.android.bluetooth.flags.Flags; 34 import com.android.compatibility.common.util.AdoptShellPermissionsRule; 35 36 import org.junit.Rule; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.util.UUID; 41 import java.util.concurrent.CompletableFuture; 42 import java.util.concurrent.TimeUnit; 43 44 @RunWith(AndroidJUnit4.class) 45 public class LeLegacyAdvertisingTest { 46 private static final int TIMEOUT_MS = 1_000; 47 48 @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); 49 50 @Rule 51 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 52 53 @RequiresFlagsEnabled(Flags.FLAG_BLE_CHECK_DATA_LENGTH_ON_LEGACY_ADVERTISING) 54 @Test setAdvertisingDataOver31Bytes()55 public void setAdvertisingDataOver31Bytes() throws Exception { 56 final BluetoothLeAdvertiser advertiser = 57 BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser(); 58 59 // Set legacy scan mode 60 AdvertisingSetParameters params = 61 new AdvertisingSetParameters.Builder() 62 .setLegacyMode(true) 63 .setScannable(true) 64 .setInterval(AdvertisingSetParameters.INTERVAL_HIGH) 65 .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MEDIUM) 66 .build(); 67 68 AdvertiseData advertiseData = 69 new AdvertiseData.Builder() 70 .addServiceUuid(new ParcelUuid(UUID.randomUUID())) 71 .build(); 72 73 final CompletableFuture<Integer> future = new CompletableFuture<>(); 74 75 AdvertisingSetCallback callback = 76 new AdvertisingSetCallback() { 77 @Override 78 public void onAdvertisingSetStarted( 79 AdvertisingSet advertisingSet, int txPower, int status) { 80 // Should be greater than 31 81 int advertisingDataLengthWhichExceedsLimit = 50; 82 advertisingSet.setAdvertisingData( 83 createAdvertiseData(advertisingDataLengthWhichExceedsLimit)); 84 } 85 86 @Override 87 public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) { 88 future.complete(status); 89 } 90 }; 91 92 try { 93 advertiser.startAdvertisingSet(params, advertiseData, null, null, null, callback); 94 future.completeOnTimeout(null, TIMEOUT_MS, TimeUnit.MILLISECONDS).join(); 95 96 Integer setAdvertingDataResult = future.get(); 97 assertThat(setAdvertingDataResult).isNotNull(); 98 assertThat(setAdvertingDataResult) 99 .isEqualTo(AdvertisingSetCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); 100 } finally { 101 advertiser.stopAdvertisingSet(callback); 102 } 103 } 104 105 @RequiresFlagsEnabled(Flags.FLAG_BLE_CHECK_DATA_LENGTH_ON_LEGACY_ADVERTISING) 106 @Test setScanResponseDataOver31Bytes()107 public void setScanResponseDataOver31Bytes() throws Exception { 108 final BluetoothLeAdvertiser advertiser = 109 BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser(); 110 111 // Set legacy scan mode 112 AdvertisingSetParameters params = 113 new AdvertisingSetParameters.Builder() 114 .setLegacyMode(true) 115 .setScannable(true) 116 .setInterval(AdvertisingSetParameters.INTERVAL_HIGH) 117 .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MEDIUM) 118 .build(); 119 120 AdvertiseData advertiseData = 121 new AdvertiseData.Builder() 122 .addServiceUuid(new ParcelUuid(UUID.randomUUID())) 123 .build(); 124 125 final CompletableFuture<Integer> future = new CompletableFuture<>(); 126 127 AdvertisingSetCallback callback = 128 new AdvertisingSetCallback() { 129 @Override 130 public void onAdvertisingSetStarted( 131 AdvertisingSet advertisingSet, int txPower, int status) { 132 // Should be greater than 31 133 int scanResponseDataLengthWhichExceedsLimit = 50; 134 advertisingSet.setScanResponseData( 135 createAdvertiseData(scanResponseDataLengthWhichExceedsLimit)); 136 } 137 138 @Override 139 public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) { 140 future.complete(status); 141 } 142 }; 143 144 try { 145 advertiser.startAdvertisingSet(params, advertiseData, null, null, null, callback); 146 future.completeOnTimeout(null, TIMEOUT_MS, TimeUnit.MILLISECONDS).join(); 147 148 Integer setScanResponseResult = future.get(); 149 assertThat(setScanResponseResult).isNotNull(); 150 assertThat(setScanResponseResult) 151 .isEqualTo(AdvertisingSetCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); 152 } finally { 153 advertiser.stopAdvertisingSet(callback); 154 } 155 } 156 createAdvertiseData(int length)157 private AdvertiseData createAdvertiseData(int length) { 158 if (length <= 4) { 159 return null; 160 } 161 162 // Create an arbitrary manufacturer specific data 163 int manufacturerId = BluetoothAssignedNumbers.GOOGLE; 164 byte[] manufacturerSpecificData = new byte[length - 4]; 165 for (int i = 0; i < manufacturerSpecificData.length; i++) { 166 manufacturerSpecificData[i] = (byte) i; 167 } 168 169 return new AdvertiseData.Builder() 170 .addManufacturerData(manufacturerId, manufacturerSpecificData) 171 .build(); 172 } 173 } 174