Merge changes from topic "cherrypicker-L22800030000756195:N75200030012855151" into main

* changes:
  [nearby] Add nearby_enable_ble_in_init flag
  Revert "[nearby] Add disable logic"
  [nearby] Add disable logic
  [nearby] Log changes
  [nearby] Sync discoveryTimestamp field name
  [nearby] Enable BLE when init
  [nearby] Add logs to broadcaster
  [nearby] Add discoveryTimestamp field
  [nearby] Fix flakeness in the unit test
  [nearby][clean up] Remove useless legacy code
  [nearby] Fix the user-debug only test
  [nearby] Catches NPE in ChreDiscoveryProvider
  [nearby] Update README to add build env script
This commit is contained in:
Xinyi Zhou
2023-12-13 19:51:46 +00:00
committed by Gerrit Code Review
13 changed files with 286 additions and 32 deletions

View File

@@ -49,6 +49,7 @@ Then, add the jar in IDE as below.
```sh ```sh
Build unbundled module using banchan Build unbundled module using banchan
$ source build/envsetup.sh
$ banchan com.google.android.tethering mainline_modules_arm64 $ banchan com.google.android.tethering mainline_modules_arm64
$ m apps_only dist $ m apps_only dist
$ adb install out/dist/com.google.android.tethering.apex $ adb install out/dist/com.google.android.tethering.apex

View File

@@ -284,6 +284,8 @@ public class NearbyManager {
*/ */
public void queryOffloadCapability(@NonNull @CallbackExecutor Executor executor, public void queryOffloadCapability(@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<OffloadCapability> callback) { @NonNull Consumer<OffloadCapability> callback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
try { try {
mService.queryOffloadCapability(new OffloadTransport(executor, callback)); mService.queryOffloadCapability(new OffloadTransport(executor, callback));
} catch (RemoteException e) { } catch (RemoteException e) {

View File

@@ -54,6 +54,11 @@ public class NearbyConfiguration {
public static final String NEARBY_REFACTOR_DISCOVERY_MANAGER = public static final String NEARBY_REFACTOR_DISCOVERY_MANAGER =
"nearby_refactor_discovery_manager"; "nearby_refactor_discovery_manager";
/**
* Flag to guard enable BLE during Nearby Service init time.
*/
public static final String NEARBY_ENABLE_BLE_IN_INIT = "nearby_enable_ble_in_init";
private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE); private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
private final DeviceConfigListener mDeviceConfigListener = new DeviceConfigListener(); private final DeviceConfigListener mDeviceConfigListener = new DeviceConfigListener();
@@ -67,6 +72,8 @@ public class NearbyConfiguration {
private boolean mSupportTestApp; private boolean mSupportTestApp;
@GuardedBy("mDeviceConfigLock") @GuardedBy("mDeviceConfigLock")
private boolean mRefactorDiscoveryManager; private boolean mRefactorDiscoveryManager;
@GuardedBy("mDeviceConfigLock")
private boolean mEnableBleInInit;
public NearbyConfiguration() { public NearbyConfiguration() {
mDeviceConfigListener.start(); mDeviceConfigListener.start();
@@ -131,6 +138,15 @@ public class NearbyConfiguration {
} }
} }
/**
* @return {@code true} if enableBLE() is called during NearbyService init time.
*/
public boolean enableBleInInit() {
synchronized (mDeviceConfigLock) {
return mEnableBleInInit;
}
}
private class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener { private class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
public void start() { public void start() {
DeviceConfig.addOnPropertiesChangedListener(getNamespace(), DeviceConfig.addOnPropertiesChangedListener(getNamespace(),
@@ -149,6 +165,8 @@ public class NearbyConfiguration {
NEARBY_SUPPORT_TEST_APP, false /* defaultValue */); NEARBY_SUPPORT_TEST_APP, false /* defaultValue */);
mRefactorDiscoveryManager = getDeviceConfigBoolean( mRefactorDiscoveryManager = getDeviceConfigBoolean(
NEARBY_REFACTOR_DISCOVERY_MANAGER, false /* defaultValue */); NEARBY_REFACTOR_DISCOVERY_MANAGER, false /* defaultValue */);
mEnableBleInInit = getDeviceConfigBoolean(
NEARBY_ENABLE_BLE_IN_INIT, true /* defaultValue */);
} }
} }
} }

View File

@@ -21,6 +21,7 @@ import static android.nearby.ScanRequest.SCAN_TYPE_NEARBY_PRESENCE;
import static com.android.server.nearby.NearbyService.TAG; import static com.android.server.nearby.NearbyService.TAG;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.bluetooth.BluetoothAdapter;
import android.content.Context; import android.content.Context;
import android.nearby.DataElement; import android.nearby.DataElement;
import android.nearby.IScanListener; import android.nearby.IScanListener;
@@ -35,6 +36,7 @@ import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.server.nearby.NearbyConfiguration;
import com.android.server.nearby.injector.Injector; import com.android.server.nearby.injector.Injector;
import com.android.server.nearby.managers.registration.DiscoveryRegistration; import com.android.server.nearby.managers.registration.DiscoveryRegistration;
import com.android.server.nearby.provider.AbstractDiscoveryProvider; import com.android.server.nearby.provider.AbstractDiscoveryProvider;
@@ -66,6 +68,7 @@ public class DiscoveryProviderManager extends
private final BleDiscoveryProvider mBleDiscoveryProvider; private final BleDiscoveryProvider mBleDiscoveryProvider;
private final Injector mInjector; private final Injector mInjector;
private final Executor mExecutor; private final Executor mExecutor;
private final NearbyConfiguration mNearbyConfiguration;
public DiscoveryProviderManager(Context context, Injector injector) { public DiscoveryProviderManager(Context context, Injector injector) {
Log.v(TAG, "DiscoveryProviderManager: "); Log.v(TAG, "DiscoveryProviderManager: ");
@@ -75,6 +78,7 @@ public class DiscoveryProviderManager extends
mChreDiscoveryProvider = new ChreDiscoveryProvider(mContext, mChreDiscoveryProvider = new ChreDiscoveryProvider(mContext,
new ChreCommunication(injector, mContext, mExecutor), mExecutor); new ChreCommunication(injector, mContext, mExecutor), mExecutor);
mInjector = injector; mInjector = injector;
mNearbyConfiguration = new NearbyConfiguration();
} }
@VisibleForTesting @VisibleForTesting
@@ -86,6 +90,7 @@ public class DiscoveryProviderManager extends
mInjector = injector; mInjector = injector;
mBleDiscoveryProvider = bleDiscoveryProvider; mBleDiscoveryProvider = bleDiscoveryProvider;
mChreDiscoveryProvider = chreDiscoveryProvider; mChreDiscoveryProvider = chreDiscoveryProvider;
mNearbyConfiguration = new NearbyConfiguration();
} }
private static boolean isChreOnly(Set<ScanFilter> scanFilters) { private static boolean isChreOnly(Set<ScanFilter> scanFilters) {
@@ -141,6 +146,10 @@ public class DiscoveryProviderManager extends
/** Called after boot completed. */ /** Called after boot completed. */
public void init() { public void init() {
// Register BLE only scan when Bluetooth is turned off
if (mNearbyConfiguration.enableBleInInit()) {
setBleScanEnabled();
}
if (mInjector.getContextHubManager() != null) { if (mInjector.getContextHubManager() != null) {
mChreDiscoveryProvider.init(); mChreDiscoveryProvider.init();
} }
@@ -242,7 +251,7 @@ public class DiscoveryProviderManager extends
@GuardedBy("mMultiplexerLock") @GuardedBy("mMultiplexerLock")
private void startBleProvider(Set<ScanFilter> scanFilters) { private void startBleProvider(Set<ScanFilter> scanFilters) {
if (!mBleDiscoveryProvider.getController().isStarted()) { if (!mBleDiscoveryProvider.getController().isStarted()) {
Log.d(TAG, "DiscoveryProviderManager starts Ble scanning."); Log.d(TAG, "DiscoveryProviderManager starts BLE scanning.");
mBleDiscoveryProvider.getController().setListener(this); mBleDiscoveryProvider.getController().setListener(this);
mBleDiscoveryProvider.getController().setProviderScanMode(mMerged.getScanMode()); mBleDiscoveryProvider.getController().setProviderScanMode(mMerged.getScanMode());
mBleDiscoveryProvider.getController().setProviderScanFilters( mBleDiscoveryProvider.getController().setProviderScanFilters(
@@ -313,4 +322,29 @@ public class DiscoveryProviderManager extends
public void onMergedRegistrationsUpdated() { public void onMergedRegistrationsUpdated() {
invalidateProviderScanMode(); invalidateProviderScanMode();
} }
/**
* Registers Nearby service to Ble scan if Bluetooth is off. (Even when Bluetooth is off)
* @return {@code true} when Nearby currently can scan through Bluetooth or Ble or successfully
* registers Nearby service to Ble scan when Blutooth is off.
*/
public boolean setBleScanEnabled() {
BluetoothAdapter adapter = mInjector.getBluetoothAdapter();
if (adapter == null) {
Log.e(TAG, "BluetoothAdapter is null.");
return false;
}
if (adapter.isEnabled() || adapter.isLeEnabled()) {
return true;
}
if (!adapter.isBleScanAlwaysAvailable()) {
Log.v(TAG, "Ble always on scan is disabled.");
return false;
}
if (!adapter.enableBLE()) {
Log.e(TAG, "Failed to register Ble scan.");
return false;
}
return true;
}
} }

View File

@@ -22,6 +22,7 @@ import static com.android.server.nearby.NearbyService.TAG;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context; import android.content.Context;
import android.nearby.DataElement; import android.nearby.DataElement;
import android.nearby.IScanListener; import android.nearby.IScanListener;
@@ -38,6 +39,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.server.nearby.NearbyConfiguration;
import com.android.server.nearby.injector.Injector; import com.android.server.nearby.injector.Injector;
import com.android.server.nearby.metrics.NearbyMetrics; import com.android.server.nearby.metrics.NearbyMetrics;
import com.android.server.nearby.presence.PresenceDiscoveryResult; import com.android.server.nearby.presence.PresenceDiscoveryResult;
@@ -69,6 +71,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
private final Context mContext; private final Context mContext;
private final BleDiscoveryProvider mBleDiscoveryProvider; private final BleDiscoveryProvider mBleDiscoveryProvider;
private final Injector mInjector; private final Injector mInjector;
private final NearbyConfiguration mNearbyConfiguration;
@ScanRequest.ScanMode @ScanRequest.ScanMode
private int mScanMode; private int mScanMode;
@GuardedBy("mLock") @GuardedBy("mLock")
@@ -83,6 +86,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
mContext, new ChreCommunication(injector, mContext, executor), executor); mContext, new ChreCommunication(injector, mContext, executor), executor);
mScanTypeScanListenerRecordMap = new HashMap<>(); mScanTypeScanListenerRecordMap = new HashMap<>();
mInjector = injector; mInjector = injector;
mNearbyConfiguration = new NearbyConfiguration();
Log.v(TAG, "DiscoveryProviderManagerLegacy: "); Log.v(TAG, "DiscoveryProviderManagerLegacy: ");
} }
@@ -96,6 +100,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
mBleDiscoveryProvider = bleDiscoveryProvider; mBleDiscoveryProvider = bleDiscoveryProvider;
mChreDiscoveryProvider = chreDiscoveryProvider; mChreDiscoveryProvider = chreDiscoveryProvider;
mScanTypeScanListenerRecordMap = scanTypeScanListenerRecordMap; mScanTypeScanListenerRecordMap = scanTypeScanListenerRecordMap;
mNearbyConfiguration = new NearbyConfiguration();
} }
private static boolean isChreOnly(List<ScanFilter> scanFilters) { private static boolean isChreOnly(List<ScanFilter> scanFilters) {
@@ -142,18 +147,18 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
for (IBinder listenerBinder : mScanTypeScanListenerRecordMap.keySet()) { for (IBinder listenerBinder : mScanTypeScanListenerRecordMap.keySet()) {
ScanListenerRecord record = mScanTypeScanListenerRecordMap.get(listenerBinder); ScanListenerRecord record = mScanTypeScanListenerRecordMap.get(listenerBinder);
if (record == null) { if (record == null) {
Log.w(TAG, "DiscoveryProviderManager cannot find the scan record."); Log.w(TAG, "DiscoveryProviderManagerLegacy cannot find the scan record.");
continue; continue;
} }
CallerIdentity callerIdentity = record.getCallerIdentity(); CallerIdentity callerIdentity = record.getCallerIdentity();
if (!DiscoveryPermissions.noteDiscoveryResultDelivery( if (!DiscoveryPermissions.noteDiscoveryResultDelivery(
appOpsManager, callerIdentity)) { appOpsManager, callerIdentity)) {
Log.w(TAG, "[DiscoveryProviderManager] scan permission revoked " Log.w(TAG, "[DiscoveryProviderManagerLegacy] scan permission revoked "
+ "- not forwarding results"); + "- not forwarding results");
try { try {
record.getScanListener().onError(ScanCallback.ERROR_PERMISSION_DENIED); record.getScanListener().onError(ScanCallback.ERROR_PERMISSION_DENIED);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, "DiscoveryProviderManager failed to report error.", e); Log.w(TAG, "DiscoveryProviderManagerLegacy failed to report error.", e);
} }
return; return;
} }
@@ -180,7 +185,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
NearbyMetrics.logScanDeviceDiscovered( NearbyMetrics.logScanDeviceDiscovered(
record.hashCode(), record.getScanRequest(), nearbyDevice); record.hashCode(), record.getScanRequest(), nearbyDevice);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, "DiscoveryProviderManager failed to report onDiscovered.", e); Log.w(TAG, "DiscoveryProviderManagerLegacy failed to report onDiscovered.", e);
} }
} }
} }
@@ -193,18 +198,18 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
for (IBinder listenerBinder : mScanTypeScanListenerRecordMap.keySet()) { for (IBinder listenerBinder : mScanTypeScanListenerRecordMap.keySet()) {
ScanListenerRecord record = mScanTypeScanListenerRecordMap.get(listenerBinder); ScanListenerRecord record = mScanTypeScanListenerRecordMap.get(listenerBinder);
if (record == null) { if (record == null) {
Log.w(TAG, "DiscoveryProviderManager cannot find the scan record."); Log.w(TAG, "DiscoveryProviderManagerLegacy cannot find the scan record.");
continue; continue;
} }
CallerIdentity callerIdentity = record.getCallerIdentity(); CallerIdentity callerIdentity = record.getCallerIdentity();
if (!DiscoveryPermissions.noteDiscoveryResultDelivery( if (!DiscoveryPermissions.noteDiscoveryResultDelivery(
appOpsManager, callerIdentity)) { appOpsManager, callerIdentity)) {
Log.w(TAG, "[DiscoveryProviderManager] scan permission revoked " Log.w(TAG, "[DiscoveryProviderManagerLegacy] scan permission revoked "
+ "- not forwarding results"); + "- not forwarding results");
try { try {
record.getScanListener().onError(ScanCallback.ERROR_PERMISSION_DENIED); record.getScanListener().onError(ScanCallback.ERROR_PERMISSION_DENIED);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, "DiscoveryProviderManager failed to report error.", e); Log.w(TAG, "DiscoveryProviderManagerLegacy failed to report error.", e);
} }
return; return;
} }
@@ -212,7 +217,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
try { try {
record.getScanListener().onError(errorCode); record.getScanListener().onError(errorCode);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, "DiscoveryProviderManager failed to report onError.", e); Log.w(TAG, "DiscoveryProviderManagerLegacy failed to report onError.", e);
} }
} }
} }
@@ -220,6 +225,10 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
/** Called after boot completed. */ /** Called after boot completed. */
public void init() { public void init() {
// Register BLE only scan when Bluetooth is turned off
if (mNearbyConfiguration.enableBleInInit()) {
setBleScanEnabled();
}
if (mInjector.getContextHubManager() != null) { if (mInjector.getContextHubManager() != null) {
mChreDiscoveryProvider.init(); mChreDiscoveryProvider.init();
} }
@@ -293,10 +302,10 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
if (listenerBinder != null && deathRecipient != null) { if (listenerBinder != null && deathRecipient != null) {
listenerBinder.unlinkToDeath(removedRecord.getDeathRecipient(), 0); listenerBinder.unlinkToDeath(removedRecord.getDeathRecipient(), 0);
} }
Log.v(TAG, "DiscoveryProviderManager unregistered scan listener."); Log.v(TAG, "DiscoveryProviderManagerLegacy unregistered scan listener.");
NearbyMetrics.logScanStopped(removedRecord.hashCode(), removedRecord.getScanRequest()); NearbyMetrics.logScanStopped(removedRecord.hashCode(), removedRecord.getScanRequest());
if (mScanTypeScanListenerRecordMap.isEmpty()) { if (mScanTypeScanListenerRecordMap.isEmpty()) {
Log.v(TAG, "DiscoveryProviderManager stops provider because there is no " Log.v(TAG, "DiscoveryProviderManagerLegacy stops provider because there is no "
+ "scan listener registered."); + "scan listener registered.");
stopProviders(); stopProviders();
return; return;
@@ -306,8 +315,8 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
// Removes current highest scan mode requested and sets the next highest scan mode. // Removes current highest scan mode requested and sets the next highest scan mode.
if (removedRecord.getScanRequest().getScanMode() == mScanMode) { if (removedRecord.getScanRequest().getScanMode() == mScanMode) {
Log.v(TAG, "DiscoveryProviderManager starts to find the new highest scan mode " Log.v(TAG, "DiscoveryProviderManagerLegacy starts to find the new highest "
+ "because the highest scan mode listener was unregistered."); + "scan mode because the highest scan mode listener was unregistered.");
@ScanRequest.ScanMode int highestScanModeRequested = ScanRequest.SCAN_MODE_NO_POWER; @ScanRequest.ScanMode int highestScanModeRequested = ScanRequest.SCAN_MODE_NO_POWER;
// find the next highest scan mode; // find the next highest scan mode;
for (ScanListenerRecord record : mScanTypeScanListenerRecordMap.values()) { for (ScanListenerRecord record : mScanTypeScanListenerRecordMap.values()) {
@@ -377,7 +386,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
private void startBleProvider(List<ScanFilter> scanFilters) { private void startBleProvider(List<ScanFilter> scanFilters) {
if (!mBleDiscoveryProvider.getController().isStarted()) { if (!mBleDiscoveryProvider.getController().isStarted()) {
Log.d(TAG, "DiscoveryProviderManager starts Ble scanning."); Log.d(TAG, "DiscoveryProviderManagerLegacy starts BLE scanning.");
mBleDiscoveryProvider.getController().setListener(this); mBleDiscoveryProvider.getController().setListener(this);
mBleDiscoveryProvider.getController().setProviderScanMode(mScanMode); mBleDiscoveryProvider.getController().setProviderScanMode(mScanMode);
mBleDiscoveryProvider.getController().setProviderScanFilters(scanFilters); mBleDiscoveryProvider.getController().setProviderScanFilters(scanFilters);
@@ -387,7 +396,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
@VisibleForTesting @VisibleForTesting
void startChreProvider(List<ScanFilter> scanFilters) { void startChreProvider(List<ScanFilter> scanFilters) {
Log.d(TAG, "DiscoveryProviderManager starts CHRE scanning."); Log.d(TAG, "DiscoveryProviderManagerLegacy starts CHRE scanning.");
mChreDiscoveryProvider.getController().setProviderScanFilters(scanFilters); mChreDiscoveryProvider.getController().setProviderScanFilters(scanFilters);
mChreDiscoveryProvider.getController().setProviderScanMode(mScanMode); mChreDiscoveryProvider.getController().setProviderScanMode(mScanMode);
mChreDiscoveryProvider.getController().start(); mChreDiscoveryProvider.getController().start();
@@ -503,4 +512,29 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider
unregisterScanListener(listener); unregisterScanListener(listener);
} }
} }
/**
* Registers Nearby service to Ble scan if Bluetooth is off. (Even when Bluetooth is off)
* @return {@code true} when Nearby currently can scan through Bluetooth or Ble or successfully
* registers Nearby service to Ble scan when Blutooth is off.
*/
public boolean setBleScanEnabled() {
BluetoothAdapter adapter = mInjector.getBluetoothAdapter();
if (adapter == null) {
Log.e(TAG, "BluetoothAdapter is null.");
return false;
}
if (adapter.isEnabled() || adapter.isLeEnabled()) {
return true;
}
if (!adapter.isBleScanAlwaysAvailable()) {
Log.v(TAG, "Ble always on scan is disabled.");
return false;
}
if (!adapter.enableBLE()) {
Log.e(TAG, "Failed to register Ble scan.");
return false;
}
return true;
}
} }

View File

@@ -85,6 +85,7 @@ public class BleBroadcastProvider extends AdvertiseCallback {
case BroadcastRequest.PRESENCE_VERSION_V0: case BroadcastRequest.PRESENCE_VERSION_V0:
bluetoothLeAdvertiser.startAdvertising(getAdvertiseSettings(), bluetoothLeAdvertiser.startAdvertising(getAdvertiseSettings(),
advertiseData, this); advertiseData, this);
Log.v(TAG, "Start to broadcast V0 advertisement.");
break; break;
case BroadcastRequest.PRESENCE_VERSION_V1: case BroadcastRequest.PRESENCE_VERSION_V1:
if (adapter.isLeExtendedAdvertisingSupported()) { if (adapter.isLeExtendedAdvertisingSupported()) {
@@ -92,6 +93,7 @@ public class BleBroadcastProvider extends AdvertiseCallback {
getAdvertisingSetParameters(), getAdvertisingSetParameters(),
advertiseData, advertiseData,
null, null, null, mAdvertisingSetCallback); null, null, null, mAdvertisingSetCallback);
Log.v(TAG, "Start to broadcast V1 advertisement.");
} else { } else {
Log.w(TAG, "Failed to start advertising set because the chipset" Log.w(TAG, "Failed to start advertising set because the chipset"
+ " does not supports LE Extended Advertising feature."); + " does not supports LE Extended Advertising feature.");

View File

@@ -68,15 +68,6 @@ public class BleDiscoveryProvider extends AbstractDiscoveryProvider {
@GuardedBy("mLock") @GuardedBy("mLock")
@Nullable @Nullable
private List<android.nearby.ScanFilter> mScanFilters; private List<android.nearby.ScanFilter> mScanFilters;
private android.bluetooth.le.ScanCallback mScanCallbackLegacy =
new android.bluetooth.le.ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult scanResult) {
}
@Override
public void onScanFailed(int errorCode) {
}
};
private android.bluetooth.le.ScanCallback mScanCallback = private android.bluetooth.le.ScanCallback mScanCallback =
new android.bluetooth.le.ScanCallback() { new android.bluetooth.le.ScanCallback() {
@Override @Override
@@ -170,7 +161,6 @@ public class BleDiscoveryProvider extends AbstractDiscoveryProvider {
if (isBleAvailable()) { if (isBleAvailable()) {
Log.d(TAG, "BleDiscoveryProvider started"); Log.d(TAG, "BleDiscoveryProvider started");
startScan(getScanFilters(), getScanSettings(/* legacy= */ false), mScanCallback); startScan(getScanFilters(), getScanSettings(/* legacy= */ false), mScanCallback);
startScan(getScanFilters(), getScanSettings(/* legacy= */ true), mScanCallbackLegacy);
return; return;
} }
Log.w(TAG, "Cannot start BleDiscoveryProvider because Ble is not available."); Log.w(TAG, "Cannot start BleDiscoveryProvider because Ble is not available.");
@@ -187,7 +177,6 @@ public class BleDiscoveryProvider extends AbstractDiscoveryProvider {
} }
Log.v(TAG, "Ble scan stopped."); Log.v(TAG, "Ble scan stopped.");
bluetoothLeScanner.stopScan(mScanCallback); bluetoothLeScanner.stopScan(mScanCallback);
bluetoothLeScanner.stopScan(mScanCallbackLegacy);
synchronized (mLock) { synchronized (mLock) {
if (mScanFilters != null) { if (mScanFilters != null) {
mScanFilters = null; mScanFilters = null;

View File

@@ -20,6 +20,9 @@ import static android.nearby.ScanRequest.SCAN_TYPE_NEARBY_PRESENCE;
import static com.android.server.nearby.NearbyService.TAG; import static com.android.server.nearby.NearbyService.TAG;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
@@ -155,7 +158,7 @@ public class ChreDiscoveryProvider extends AbstractDiscoveryProvider {
builder.setFastPairSupported(version != ChreCommunication.INVALID_NANO_APP_VERSION); builder.setFastPairSupported(version != ChreCommunication.INVALID_NANO_APP_VERSION);
try { try {
callback.onQueryComplete(builder.build()); callback.onQueryComplete(builder.build());
} catch (RemoteException e) { } catch (RemoteException | NullPointerException e) {
e.printStackTrace(); e.printStackTrace();
} }
}); });
@@ -350,7 +353,11 @@ public class ChreDiscoveryProvider extends AbstractDiscoveryProvider {
DataElement.DataType.ACTION, DataElement.DataType.ACTION,
new byte[]{(byte) filterResult.getIntent()})); new byte[]{(byte) filterResult.getIntent()}));
} }
if (filterResult.hasTimestampNs()) {
presenceDeviceBuilder
.setDiscoveryTimestampMillis(MILLISECONDS.convert(
filterResult.getTimestampNs(), NANOSECONDS));
}
PublicCredential publicCredential = PublicCredential publicCredential =
new PublicCredential.Builder( new PublicCredential.Builder(
secretId, secretId,

View File

@@ -115,6 +115,9 @@ message BleFilterResult {
repeated DataElement data_element = 7; repeated DataElement data_element = 7;
optional bytes ble_service_data = 8; optional bytes ble_service_data = 8;
optional ResultType result_type = 9; optional ResultType result_type = 9;
// Timestamp when the device is discovered, in nanoseconds,
// relative to Android SystemClock.elapsedRealtimeNanos().
optional uint64 timestamp_ns = 10;
} }
message BleFilterResults { message BleFilterResults {

View File

@@ -16,6 +16,7 @@
package com.android.server.nearby.managers; package com.android.server.nearby.managers;
import static android.Manifest.permission.READ_DEVICE_CONFIG;
import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE; import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE;
import static android.nearby.ScanRequest.SCAN_TYPE_NEARBY_PRESENCE; import static android.nearby.ScanRequest.SCAN_TYPE_NEARBY_PRESENCE;
@@ -23,10 +24,12 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context; import android.content.Context;
import android.nearby.DataElement; import android.nearby.DataElement;
import android.nearby.IScanListener; import android.nearby.IScanListener;
@@ -36,6 +39,8 @@ import android.nearby.PublicCredential;
import android.nearby.ScanRequest; import android.nearby.ScanRequest;
import android.os.IBinder; import android.os.IBinder;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.nearby.injector.Injector; import com.android.server.nearby.injector.Injector;
import com.android.server.nearby.provider.BleDiscoveryProvider; import com.android.server.nearby.provider.BleDiscoveryProvider;
import com.android.server.nearby.provider.ChreCommunication; import com.android.server.nearby.provider.ChreCommunication;
@@ -86,6 +91,8 @@ public class DiscoveryProviderManagerLegacyTest {
DiscoveryProviderManagerLegacy.ScanListenerDeathRecipient mScanListenerDeathRecipient; DiscoveryProviderManagerLegacy.ScanListenerDeathRecipient mScanListenerDeathRecipient;
@Mock @Mock
IBinder mIBinder; IBinder mIBinder;
@Mock
BluetoothAdapter mBluetoothAdapter;
private DiscoveryProviderManagerLegacy mDiscoveryProviderManager; private DiscoveryProviderManagerLegacy mDiscoveryProviderManager;
private Map<IBinder, DiscoveryProviderManagerLegacy.ScanListenerRecord> private Map<IBinder, DiscoveryProviderManagerLegacy.ScanListenerRecord>
mScanTypeScanListenerRecordMap; mScanTypeScanListenerRecordMap;
@@ -135,10 +142,15 @@ public class DiscoveryProviderManagerLegacyTest {
@Before @Before
public void setup() { public void setup() {
InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
READ_DEVICE_CONFIG);
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
when(mInjector.getAppOpsManager()).thenReturn(mAppOpsManager); when(mInjector.getAppOpsManager()).thenReturn(mAppOpsManager);
when(mInjector.getBluetoothAdapter()).thenReturn(mBluetoothAdapter);
when(mBleDiscoveryProvider.getController()).thenReturn(mBluetoothController); when(mBleDiscoveryProvider.getController()).thenReturn(mBluetoothController);
when(mChreDiscoveryProvider.getController()).thenReturn(mChreController); when(mChreDiscoveryProvider.getController()).thenReturn(mChreController);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true);
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
mScanTypeScanListenerRecordMap = new HashMap<>(); mScanTypeScanListenerRecordMap = new HashMap<>();
mDiscoveryProviderManager = mDiscoveryProviderManager =
@@ -163,6 +175,13 @@ public class DiscoveryProviderManagerLegacyTest {
mDiscoveryProviderManager.invalidateProviderScanMode(); mDiscoveryProviderManager.invalidateProviderScanMode();
} }
@Test
public void test_enableBleWhenBleOff() throws Exception {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
mDiscoveryProviderManager.init();
verify(mBluetoothAdapter, times(1)).enableBLE();
}
@Test @Test
public void testStartProviders_chreOnlyChreAvailable_bleProviderNotStarted() { public void testStartProviders_chreOnlyChreAvailable_bleProviderNotStarted() {
when(mChreDiscoveryProvider.available()).thenReturn(true); when(mChreDiscoveryProvider.available()).thenReturn(true);
@@ -375,4 +394,62 @@ public class DiscoveryProviderManagerLegacyTest {
.isTrue(); .isTrue();
assertThat(manager.mChreDiscoveryProvider.getFiltersLocked()).isNotNull(); assertThat(manager.mChreDiscoveryProvider.getFiltersLocked()).isNotNull();
} }
@Test
public void isBluetoothEnabledTest_bluetoothEnabled() {
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(false);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true);
when(mBluetoothAdapter.enableBLE()).thenReturn(true);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue();
}
@Test
public void isBluetoothEnabledTest_bleEnabled() {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(true);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true);
when(mBluetoothAdapter.enableBLE()).thenReturn(true);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue();
}
@Test
public void enabledTest_enabled() {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(false);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true);
when(mBluetoothAdapter.enableBLE()).thenReturn(true);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue();
}
@Test
public void enabledTest_enableFailed() {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(false);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true);
when(mBluetoothAdapter.enableBLE()).thenReturn(false);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isFalse();
}
@Test
public void enabledTest_scanIsOn() {
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(false);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(false);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue();
}
@Test
public void enabledTest_failed() {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(false);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(false);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isFalse();
}
} }

View File

@@ -16,6 +16,7 @@
package com.android.server.nearby.managers; package com.android.server.nearby.managers;
import static android.Manifest.permission.READ_DEVICE_CONFIG;
import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE; import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE;
import static android.nearby.ScanRequest.SCAN_TYPE_NEARBY_PRESENCE; import static android.nearby.ScanRequest.SCAN_TYPE_NEARBY_PRESENCE;
@@ -24,10 +25,12 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset; import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context; import android.content.Context;
import android.nearby.DataElement; import android.nearby.DataElement;
import android.nearby.IScanListener; import android.nearby.IScanListener;
@@ -37,6 +40,8 @@ import android.nearby.PublicCredential;
import android.nearby.ScanRequest; import android.nearby.ScanRequest;
import android.os.IBinder; import android.os.IBinder;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.nearby.injector.Injector; import com.android.server.nearby.injector.Injector;
import com.android.server.nearby.provider.BleDiscoveryProvider; import com.android.server.nearby.provider.BleDiscoveryProvider;
import com.android.server.nearby.provider.ChreCommunication; import com.android.server.nearby.provider.ChreCommunication;
@@ -80,6 +85,8 @@ public class DiscoveryProviderManagerTest {
CallerIdentity mCallerIdentity; CallerIdentity mCallerIdentity;
@Mock @Mock
IBinder mIBinder; IBinder mIBinder;
@Mock
BluetoothAdapter mBluetoothAdapter;
private Executor mExecutor; private Executor mExecutor;
private DiscoveryProviderManager mDiscoveryProviderManager; private DiscoveryProviderManager mDiscoveryProviderManager;
@@ -128,12 +135,17 @@ public class DiscoveryProviderManagerTest {
@Before @Before
public void setup() { public void setup() {
InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
READ_DEVICE_CONFIG);
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mExecutor = Executors.newSingleThreadExecutor(); mExecutor = Executors.newSingleThreadExecutor();
when(mInjector.getAppOpsManager()).thenReturn(mAppOpsManager); when(mInjector.getAppOpsManager()).thenReturn(mAppOpsManager);
when(mBleDiscoveryProvider.getController()).thenReturn(mBluetoothController); when(mBleDiscoveryProvider.getController()).thenReturn(mBluetoothController);
when(mChreDiscoveryProvider.getController()).thenReturn(mChreController); when(mChreDiscoveryProvider.getController()).thenReturn(mChreController);
when(mScanListener.asBinder()).thenReturn(mIBinder); when(mScanListener.asBinder()).thenReturn(mIBinder);
when(mInjector.getBluetoothAdapter()).thenReturn(mBluetoothAdapter);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true);
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
mDiscoveryProviderManager = mDiscoveryProviderManager =
new DiscoveryProviderManager(mContext, mExecutor, mInjector, new DiscoveryProviderManager(mContext, mExecutor, mInjector,
@@ -156,6 +168,13 @@ public class DiscoveryProviderManagerTest {
mDiscoveryProviderManager.invalidateProviderScanMode(); mDiscoveryProviderManager.invalidateProviderScanMode();
} }
@Test
public void test_enableBleWhenBleOff() throws Exception {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
mDiscoveryProviderManager.init();
verify(mBluetoothAdapter, times(1)).enableBLE();
}
@Test @Test
public void testStartProviders_chreOnlyChreAvailable_bleProviderNotStarted() { public void testStartProviders_chreOnlyChreAvailable_bleProviderNotStarted() {
reset(mBluetoothController); reset(mBluetoothController);
@@ -336,4 +355,62 @@ public class DiscoveryProviderManagerTest {
.isTrue(); .isTrue();
assertThat(manager.mChreDiscoveryProvider.getFiltersLocked()).isNotNull(); assertThat(manager.mChreDiscoveryProvider.getFiltersLocked()).isNotNull();
} }
@Test
public void isBluetoothEnabledTest_bluetoothEnabled() {
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(false);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true);
when(mBluetoothAdapter.enableBLE()).thenReturn(true);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue();
}
@Test
public void isBluetoothEnabledTest_bleEnabled() {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(true);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true);
when(mBluetoothAdapter.enableBLE()).thenReturn(true);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue();
}
@Test
public void enabledTest_enabled() {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(false);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true);
when(mBluetoothAdapter.enableBLE()).thenReturn(true);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue();
}
@Test
public void enabledTest_enableFailed() {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(false);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true);
when(mBluetoothAdapter.enableBLE()).thenReturn(false);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isFalse();
}
@Test
public void enabledTest_scanIsOn() {
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(false);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(false);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue();
}
@Test
public void enabledTest_failed() {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
when(mBluetoothAdapter.isLeEnabled()).thenReturn(false);
when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(false);
assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isFalse();
}
} }

View File

@@ -16,6 +16,7 @@
package com.android.server.nearby.provider; package com.android.server.nearby.provider;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.eq; import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
@@ -69,7 +70,7 @@ public class BleBroadcastProviderTest {
AdvertiseSettings settings = new AdvertiseSettings.Builder().build(); AdvertiseSettings settings = new AdvertiseSettings.Builder().build();
mBleBroadcastProvider.onStartSuccess(settings); mBleBroadcastProvider.onStartSuccess(settings);
verify(mBroadcastListener).onStatusChanged(eq(BroadcastCallback.STATUS_OK)); verify(mBroadcastListener, times(any())).onStatusChanged(eq(BroadcastCallback.STATUS_OK));
} }
@Test @Test
@@ -81,7 +82,7 @@ public class BleBroadcastProviderTest {
// advertising set can not be mocked, so we will allow nulls // advertising set can not be mocked, so we will allow nulls
mBleBroadcastProvider.mAdvertisingSetCallback.onAdvertisingSetStarted(null, -30, mBleBroadcastProvider.mAdvertisingSetCallback.onAdvertisingSetStarted(null, -30,
AdvertisingSetCallback.ADVERTISE_SUCCESS); AdvertisingSetCallback.ADVERTISE_SUCCESS);
verify(mBroadcastListener).onStatusChanged(eq(BroadcastCallback.STATUS_OK)); verify(mBroadcastListener, times(any())).onStatusChanged(eq(BroadcastCallback.STATUS_OK));
} }
@Test @Test

View File

@@ -192,7 +192,7 @@ public class ChreDiscoveryProviderTest {
@Test @Test
@SdkSuppress(minSdkVersion = 32, codeName = "T") @SdkSuppress(minSdkVersion = 32, codeName = "T")
public void testOnNearbyDeviceDiscoveredWithDataElements() { public void testOnNearbyDeviceDiscoveredWithDataElements_TIME() {
// Disables the setting of test app support // Disables the setting of test app support
boolean isSupportedTestApp = getDeviceConfigBoolean( boolean isSupportedTestApp = getDeviceConfigBoolean(
NEARBY_SUPPORT_TEST_APP, false /* defaultValue */); NEARBY_SUPPORT_TEST_APP, false /* defaultValue */);
@@ -209,6 +209,7 @@ public class ChreDiscoveryProviderTest {
// First byte is length of service data, padding zeros should be thrown away. // 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 [] 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 byte [] testData = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
final long timestampNs = 1697765417070000000L;
final List<DataElement> expectedExtendedProperties = new ArrayList<>(); final List<DataElement> expectedExtendedProperties = new ArrayList<>();
expectedExtendedProperties.add(new DataElement(DATA_TYPE_CONNECTION_STATUS_KEY, expectedExtendedProperties.add(new DataElement(DATA_TYPE_CONNECTION_STATUS_KEY,
@@ -262,6 +263,7 @@ public class ChreDiscoveryProviderTest {
.setValue(ByteString.copyFrom(testData)) .setValue(ByteString.copyFrom(testData))
.setValueLength(testData.length) .setValueLength(testData.length)
) )
.setTimestampNs(timestampNs)
.build(); .build();
Blefilter.BleFilterResults results = Blefilter.BleFilterResults results =
Blefilter.BleFilterResults.newBuilder().addResult(result).build(); Blefilter.BleFilterResults.newBuilder().addResult(result).build();
@@ -285,11 +287,18 @@ public class ChreDiscoveryProviderTest {
DeviceConfig.setProperty(NAMESPACE, NEARBY_SUPPORT_TEST_APP, "true", false); DeviceConfig.setProperty(NAMESPACE, NEARBY_SUPPORT_TEST_APP, "true", false);
assertThat(new NearbyConfiguration().isTestAppSupported()).isTrue(); assertThat(new NearbyConfiguration().isTestAppSupported()).isTrue();
} }
// Nanoseconds to Milliseconds
assertThat((mNearbyDevice.getValue().getPresenceDevice())
.getDiscoveryTimestampMillis()).isEqualTo(timestampNs / 1000000);
} }
@Test @Test
@SdkSuppress(minSdkVersion = 32, codeName = "T") @SdkSuppress(minSdkVersion = 33, codeName = "T")
public void testOnNearbyDeviceDiscoveredWithTestDataElements() { public void testOnNearbyDeviceDiscoveredWithTestDataElements() {
// The feature only supports user-debug builds.
if (!Build.isDebuggable()) {
return;
}
// Enables the setting of test app support // Enables the setting of test app support
boolean isSupportedTestApp = getDeviceConfigBoolean( boolean isSupportedTestApp = getDeviceConfigBoolean(
NEARBY_SUPPORT_TEST_APP, false /* defaultValue */); NEARBY_SUPPORT_TEST_APP, false /* defaultValue */);