Allows Test Data Elements with Filter
Bug: 259299293
Test: atest NearbyUnitTests and on device test
Ignore-AOSP-First: nearby_not_in_aosp_yet
Merged-In: I2d0a537d38ac7b602bc49dcf2113c43f1b654cb2
Change-Id: I2d0a537d38ac7b602bc49dcf2113c43f1b654cb2
diff --git a/nearby/framework/java/android/nearby/DataElement.java b/nearby/framework/java/android/nearby/DataElement.java
index 4592c33..02548cb 100644
--- a/nearby/framework/java/android/nearby/DataElement.java
+++ b/nearby/framework/java/android/nearby/DataElement.java
@@ -55,7 +55,9 @@
DataType.ACCOUNT_KEY_DATA,
DataType.CONNECTION_STATUS,
DataType.BATTERY,
- DataType.SCAN_MODE
+ DataType.SCAN_MODE,
+ DataType.TEST_DE_BEGIN,
+ DataType.TEST_DE_END
})
public @interface DataType {
int BLE_SERVICE_DATA = 100;
@@ -74,6 +76,10 @@
int ACCOUNT_KEY_DATA = 9;
int CONNECTION_STATUS = 10;
int BATTERY = 11;
+ // Reserves test DE ranges from {@link DataElement.DataType#TEST_DE_BEGIN}
+ // to {@link DataElement.DataType#TEST_DE_END}, inclusive.
+ int TEST_DE_BEGIN = 256;
+ int TEST_DE_END = 260;
}
/**
@@ -109,6 +115,14 @@
}
/**
+ * @return {@code true} if this is test data element type.
+ * @hide
+ */
+ public static boolean isTestDeType(int type) {
+ return type >= DataType.TEST_DE_BEGIN && type <= DataType.TEST_DE_END;
+ }
+
+ /**
* Constructs a {@link DataElement}.
*/
public DataElement(int key, @NonNull byte[] value) {
diff --git a/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java b/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java
index 6aefae9..93acede 100644
--- a/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java
+++ b/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java
@@ -20,10 +20,6 @@
import static com.android.server.nearby.NearbyService.TAG;
-import static service.proto.Blefilter.DataElement.ElementType.DE_BATTERY_STATUS;
-import static service.proto.Blefilter.DataElement.ElementType.DE_CONNECTION_STATUS;
-import static service.proto.Blefilter.DataElement.ElementType.DE_FAST_PAIR_ACCOUNT_KEY;
-
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -41,9 +37,11 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.nearby.NearbyConfiguration;
import com.google.protobuf.ByteString;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
@@ -54,13 +52,17 @@
public class ChreDiscoveryProvider extends AbstractDiscoveryProvider {
// Nanoapp ID reserved for Nearby Presence.
/** @hide */
- @VisibleForTesting public static final long NANOAPP_ID = 0x476f6f676c001031L;
+ @VisibleForTesting
+ public static final long NANOAPP_ID = 0x476f6f676c001031L;
/** @hide */
- @VisibleForTesting public static final int NANOAPP_MESSAGE_TYPE_FILTER = 3;
+ @VisibleForTesting
+ public static final int NANOAPP_MESSAGE_TYPE_FILTER = 3;
/** @hide */
- @VisibleForTesting public static final int NANOAPP_MESSAGE_TYPE_FILTER_RESULT = 4;
+ @VisibleForTesting
+ public static final int NANOAPP_MESSAGE_TYPE_FILTER_RESULT = 4;
/** @hide */
- @VisibleForTesting public static final int NANOAPP_MESSAGE_TYPE_CONFIG = 5;
+ @VisibleForTesting
+ public static final int NANOAPP_MESSAGE_TYPE_CONFIG = 5;
private static final int FP_ACCOUNT_KEY_LENGTH = 16;
@@ -71,6 +73,7 @@
private boolean mChreStarted = false;
private Blefilter.BleFilters mFilters = null;
private Context mContext;
+ private NearbyConfiguration mNearbyConfiguration;
private final IntentFilter mIntentFilter;
// Null when the filters are never set
@GuardedBy("mLock")
@@ -101,6 +104,7 @@
/** Initialize the CHRE discovery provider. */
public void init() {
mChreCommunication.start(mChreCallback, Collections.singleton(NANOAPP_ID));
+ mNearbyConfiguration = new NearbyConfiguration();
}
@Override
@@ -162,6 +166,9 @@
for (DataElement dataElement : presenceScanFilter.getExtendedProperties()) {
if (dataElement.getKey() == DataElement.DataType.ACCOUNT_KEY_DATA) {
filterBuilder.addDataElement(toProtoDataElement(dataElement));
+ } else if (mNearbyConfiguration.isTestAppSupported()
+ && DataElement.isTestDeType(dataElement.getKey())) {
+ filterBuilder.addDataElement(toProtoDataElement(dataElement));
}
}
if (!presenceScanFilter.getPresenceActions().isEmpty()) {
@@ -177,7 +184,8 @@
private Blefilter.PublicateCertificate toProtoPublicCredential(PublicCredential credential) {
Log.d(TAG, String.format("Returns a PublicCertificate with authenticity key size %d and"
- + " encrypted metadata key tag size %d", credential.getAuthenticityKey().length,
+ + " encrypted metadata key tag size %d",
+ credential.getAuthenticityKey().length,
credential.getEncryptedMetadataKeyTag().length));
return Blefilter.PublicateCertificate.newBuilder()
.setAuthenticityKey(ByteString.copyFrom(credential.getAuthenticityKey()))
@@ -188,12 +196,13 @@
private Blefilter.DataElement toProtoDataElement(DataElement dataElement) {
return Blefilter.DataElement.newBuilder()
- .setKey(
- Blefilter.DataElement.ElementType
- .DE_FAST_PAIR_ACCOUNT_KEY)
- .setValue(ByteString.copyFrom(dataElement.getValue()))
- .setValueLength(FP_ACCOUNT_KEY_LENGTH)
- .build();
+ .setKey(Arrays.stream(Blefilter.DataElement.ElementType.values())
+ .filter(p -> p.getNumber() == dataElement.getKey())
+ .findFirst()
+ .get())
+ .setValue(ByteString.copyFrom(dataElement.getValue()))
+ .setValueLength(dataElement.getValue().length)
+ .build();
}
private void sendFilters(Blefilter.BleFilters filters) {
@@ -282,10 +291,10 @@
}
PresenceDevice.Builder presenceDeviceBuilder =
new PresenceDevice.Builder(
- String.valueOf(filterResult.hashCode()),
- salt,
- secretId,
- encryptedMetaData)
+ String.valueOf(filterResult.hashCode()),
+ salt,
+ secretId,
+ encryptedMetaData)
.setRssi(filterResult.getRssi())
.addMedium(NearbyDevice.Medium.BLE);
// Data Elements reported from nanoapp added to Data Elements.
@@ -330,11 +339,11 @@
PublicCredential publicCredential =
new PublicCredential.Builder(
- secretId,
- authenticityKey,
- publicKey,
- encryptedMetaData,
- encryptedMetaDataTag)
+ secretId,
+ authenticityKey,
+ publicKey,
+ encryptedMetaData,
+ encryptedMetaDataTag)
.build();
NearbyDeviceParcelable device =
@@ -377,6 +386,16 @@
element.getValue().substring(0, endIndex).toByteArray()));
break;
default:
+ if (mNearbyConfiguration.isTestAppSupported()
+ && DataElement.isTestDeType(element.getKey().getNumber())) {
+ presenceDeviceBuilder.addExtendedProperty(
+ new DataElement(Arrays.stream(
+ Blefilter.DataElement.ElementType.values())
+ .filter(p -> p.getNumber() == element.getKey().getNumber())
+ .findFirst()
+ .get().getNumber(),
+ element.getValue().substring(0, endIndex).toByteArray()));
+ }
break;
}
}
diff --git a/nearby/service/proto/src/presence/blefilter.proto b/nearby/service/proto/src/presence/blefilter.proto
index 6e1ba6d..9b760c1 100644
--- a/nearby/service/proto/src/presence/blefilter.proto
+++ b/nearby/service/proto/src/presence/blefilter.proto
@@ -58,10 +58,20 @@
message DataElement {
enum ElementType {
+ option allow_alias = true;
+
DE_NONE = 0;
DE_FAST_PAIR_ACCOUNT_KEY = 9;
DE_CONNECTION_STATUS = 10;
DE_BATTERY_STATUS = 11;
+ // Reserves Test DEs.
+ DE_TEST_BEGIN = 256;
+ DE_TEST_1 = 256;
+ DE_TEST_2 = 257;
+ DE_TEST_3 = 258;
+ DE_TEST_4 = 259;
+ DE_TEST_5 = 260;
+ DE_TEST_END = 260;
}
optional ElementType key = 1;
diff --git a/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java b/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java
index 270de52..d06a447 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java
@@ -16,6 +16,12 @@
package com.android.server.nearby.provider;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
+import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
+
+import static com.android.server.nearby.NearbyConfiguration.NEARBY_SUPPORT_TEST_APP;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -25,10 +31,12 @@
import android.hardware.location.NanoAppMessage;
import android.nearby.DataElement;
import android.nearby.NearbyDeviceParcelable;
+import android.provider.DeviceConfig;
import androidx.test.filters.SdkSuppress;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.server.nearby.NearbyConfiguration;
import com.android.server.nearby.presence.PresenceDiscoveryResult;
import com.google.protobuf.ByteString;
@@ -59,11 +67,20 @@
private static final int DATA_TYPE_BLUETOOTH_ADDR_KEY = 101;
private static final int DATA_TYPE_FP_ACCOUNT_KEY = 9;
private static final int DATA_TYPE_BLE_SERVICE_DATA_KEY = 100;
+ private static final int DATA_TYPE_TEST_1_KEY = 256;
+ private static final int DATA_TYPE_TEST_2_KEY = 257;
+ private static final int DATA_TYPE_TEST_3_KEY = 258;
+ private static final int DATA_TYPE_TEST_4_KEY = 259;
+ private static final int DATA_TYPE_TEST_5_KEY = 260;
private ChreDiscoveryProvider mChreDiscoveryProvider;
+
@Before
public void setUp() {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(WRITE_DEVICE_CONFIG, READ_DEVICE_CONFIG);
+
MockitoAnnotations.initMocks(this);
Context context = InstrumentationRegistry.getInstrumentation().getContext();
mChreDiscoveryProvider =
@@ -113,6 +130,14 @@
@Test
@SdkSuppress(minSdkVersion = 32, codeName = "T")
public void testOnNearbyDeviceDiscoveredWithDataElements() {
+ // Disables the setting of test app support
+ boolean isSupportedTestApp = getDeviceConfigBoolean(
+ NEARBY_SUPPORT_TEST_APP, false /* defaultValue */);
+ if (isSupportedTestApp) {
+ DeviceConfig.setProperty(NAMESPACE_TETHERING, NEARBY_SUPPORT_TEST_APP, "false", false);
+ }
+ assertThat(new NearbyConfiguration().isTestAppSupported()).isFalse();
+
final byte [] connectionStatus = new byte[] {1, 2, 3};
final byte [] batteryStatus = new byte[] {4, 5, 6};
final byte [] txPower = new byte[] {2};
@@ -120,6 +145,7 @@
final byte [] fastPairAccountKey = new byte[16];
// First byte is length of service data, padding zeros should be thrown away.
final byte [] bleServiceData = new byte[] {5, 1, 2, 3, 4, 5, 0, 0, 0, 0};
+ final byte [] testData = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
final List<DataElement> expectedExtendedProperties = new ArrayList<>();
expectedExtendedProperties.add(new DataElement(DATA_TYPE_CONNECTION_STATUS_KEY,
@@ -169,6 +195,41 @@
.setValue(ByteString.copyFrom(fastPairAccountKey))
.setValueLength(fastPairAccountKey.length)
)
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_TEST_1)
+ .setValue(ByteString.copyFrom(testData))
+ .setValueLength(testData.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_TEST_2)
+ .setValue(ByteString.copyFrom(testData))
+ .setValueLength(testData.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_TEST_3)
+ .setValue(ByteString.copyFrom(testData))
+ .setValueLength(testData.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_TEST_4)
+ .setValue(ByteString.copyFrom(testData))
+ .setValueLength(testData.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_TEST_5)
+ .setValue(ByteString.copyFrom(testData))
+ .setValueLength(testData.length)
+ )
.build();
Blefilter.BleFilterResults results =
Blefilter.BleFilterResults.newBuilder().addResult(result).build();
@@ -187,6 +248,158 @@
List<DataElement> extendedProperties = PresenceDiscoveryResult
.fromDevice(mNearbyDevice.getValue()).getExtendedProperties();
assertThat(extendedProperties).containsExactlyElementsIn(expectedExtendedProperties);
+ // Reverts the setting of test app support
+ if (isSupportedTestApp) {
+ DeviceConfig.setProperty(NAMESPACE_TETHERING, NEARBY_SUPPORT_TEST_APP, "true", false);
+ assertThat(new NearbyConfiguration().isTestAppSupported()).isTrue();
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 32, codeName = "T")
+ public void testOnNearbyDeviceDiscoveredWithTestDataElements() {
+ // Enables the setting of test app support
+ boolean isSupportedTestApp = getDeviceConfigBoolean(
+ NEARBY_SUPPORT_TEST_APP, false /* defaultValue */);
+ if (!isSupportedTestApp) {
+ DeviceConfig.setProperty(NAMESPACE_TETHERING, NEARBY_SUPPORT_TEST_APP, "true", false);
+ }
+ assertThat(new NearbyConfiguration().isTestAppSupported()).isTrue();
+
+ final byte [] connectionStatus = new byte[] {1, 2, 3};
+ final byte [] batteryStatus = new byte[] {4, 5, 6};
+ final byte [] txPower = new byte[] {2};
+ final byte [] bluetoothAddr = new byte[] {1, 2, 3, 4, 5, 6};
+ final byte [] fastPairAccountKey = new byte[16];
+ // First byte is length of service data, padding zeros should be thrown away.
+ final byte [] bleServiceData = new byte[] {5, 1, 2, 3, 4, 5, 0, 0, 0, 0};
+ final byte [] testData = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+ final List<DataElement> expectedExtendedProperties = new ArrayList<>();
+ expectedExtendedProperties.add(new DataElement(DATA_TYPE_CONNECTION_STATUS_KEY,
+ connectionStatus));
+ expectedExtendedProperties.add(new DataElement(DATA_TYPE_BATTERY_KEY, batteryStatus));
+ expectedExtendedProperties.add(new DataElement(DATA_TYPE_TX_POWER_KEY, txPower));
+ expectedExtendedProperties.add(
+ new DataElement(DATA_TYPE_BLUETOOTH_ADDR_KEY, bluetoothAddr));
+ expectedExtendedProperties.add(
+ new DataElement(DATA_TYPE_FP_ACCOUNT_KEY, fastPairAccountKey));
+ expectedExtendedProperties.add(
+ new DataElement(DATA_TYPE_BLE_SERVICE_DATA_KEY, new byte[] {1, 2, 3, 4, 5}));
+ expectedExtendedProperties.add(
+ new DataElement(DATA_TYPE_TEST_1_KEY, testData));
+ expectedExtendedProperties.add(
+ new DataElement(DATA_TYPE_TEST_2_KEY, testData));
+ expectedExtendedProperties.add(
+ new DataElement(DATA_TYPE_TEST_3_KEY, testData));
+ expectedExtendedProperties.add(
+ new DataElement(DATA_TYPE_TEST_4_KEY, testData));
+ expectedExtendedProperties.add(
+ new DataElement(DATA_TYPE_TEST_5_KEY, testData));
+
+ Blefilter.PublicCredential credential =
+ Blefilter.PublicCredential.newBuilder()
+ .setSecretId(ByteString.copyFrom(new byte[] {1}))
+ .setAuthenticityKey(ByteString.copyFrom(new byte[2]))
+ .setPublicKey(ByteString.copyFrom(new byte[3]))
+ .setEncryptedMetadata(ByteString.copyFrom(new byte[4]))
+ .setEncryptedMetadataTag(ByteString.copyFrom(new byte[5]))
+ .build();
+ Blefilter.BleFilterResult result =
+ Blefilter.BleFilterResult.newBuilder()
+ .setTxPower(2)
+ .setRssi(1)
+ .setBluetoothAddress(ByteString.copyFrom(bluetoothAddr))
+ .setBleServiceData(ByteString.copyFrom(bleServiceData))
+ .setPublicCredential(credential)
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_CONNECTION_STATUS)
+ .setValue(ByteString.copyFrom(connectionStatus))
+ .setValueLength(connectionStatus.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_BATTERY_STATUS)
+ .setValue(ByteString.copyFrom(batteryStatus))
+ .setValueLength(batteryStatus.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_FAST_PAIR_ACCOUNT_KEY)
+ .setValue(ByteString.copyFrom(fastPairAccountKey))
+ .setValueLength(fastPairAccountKey.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_TEST_1)
+ .setValue(ByteString.copyFrom(testData))
+ .setValueLength(testData.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_TEST_2)
+ .setValue(ByteString.copyFrom(testData))
+ .setValueLength(testData.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_TEST_3)
+ .setValue(ByteString.copyFrom(testData))
+ .setValueLength(testData.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_TEST_4)
+ .setValue(ByteString.copyFrom(testData))
+ .setValueLength(testData.length)
+ )
+ .addDataElement(Blefilter.DataElement.newBuilder()
+ .setKey(
+ Blefilter.DataElement.ElementType
+ .DE_TEST_5)
+ .setValue(ByteString.copyFrom(testData))
+ .setValueLength(testData.length)
+ )
+ .build();
+ Blefilter.BleFilterResults results =
+ Blefilter.BleFilterResults.newBuilder().addResult(result).build();
+ NanoAppMessage chre_message =
+ NanoAppMessage.createMessageToNanoApp(
+ ChreDiscoveryProvider.NANOAPP_ID,
+ ChreDiscoveryProvider.NANOAPP_MESSAGE_TYPE_FILTER_RESULT,
+ results.toByteArray());
+ mChreDiscoveryProvider.getController().setListener(mListener);
+ mChreDiscoveryProvider.init();
+ mChreDiscoveryProvider.onStart();
+ verify(mChreCommunication).start(mChreCallbackCaptor.capture(), any());
+ mChreCallbackCaptor.getValue().onMessageFromNanoApp(chre_message);
+ verify(mListener).onNearbyDeviceDiscovered(mNearbyDevice.capture());
+
+ List<DataElement> extendedProperties = PresenceDiscoveryResult
+ .fromDevice(mNearbyDevice.getValue()).getExtendedProperties();
+ assertThat(extendedProperties).containsExactlyElementsIn(expectedExtendedProperties);
+ // Reverts the setting of test app support
+ if (!isSupportedTestApp) {
+ DeviceConfig.setProperty(NAMESPACE_TETHERING, NEARBY_SUPPORT_TEST_APP, "false", false);
+ assertThat(new NearbyConfiguration().isTestAppSupported()).isFalse();
+ }
+ }
+
+ private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) {
+ final String value = getDeviceConfigProperty(name);
+ return value != null ? Boolean.parseBoolean(value) : defaultValue;
+ }
+
+ private String getDeviceConfigProperty(String name) {
+ return DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TETHERING, name);
}
private static class InLineExecutor implements Executor {