Merge "[DO NOT MERGE] Improvements and fixes for BLE scanning within CDM" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
f650c52876
@@ -726,4 +726,43 @@ public interface ServiceConnector<I extends IInterface> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ServiceConnector} that doesn't connect to anything.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the {@link IInterface ipc interface} for the remote service
|
||||||
|
*/
|
||||||
|
class NoOp<T extends IInterface> extends AndroidFuture<Object> implements ServiceConnector<T> {
|
||||||
|
{
|
||||||
|
completeExceptionally(new IllegalStateException("ServiceConnector is a no-op"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean run(@NonNull VoidJob<T> job) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AndroidFuture<Void> post(@NonNull VoidJob<T> job) {
|
||||||
|
return (AndroidFuture) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R> AndroidFuture<R> postForResult(@NonNull Job<T, R> job) {
|
||||||
|
return (AndroidFuture) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R> AndroidFuture<R> postAsync(@NonNull Job<T, CompletableFuture<R>> job) {
|
||||||
|
return (AndroidFuture) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AndroidFuture<T> connect() {
|
||||||
|
return (AndroidFuture) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unbind() {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,11 @@ package com.android.server.companion;
|
|||||||
import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
|
import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
|
||||||
import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
|
import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
|
||||||
import static android.content.Context.BIND_IMPORTANT;
|
import static android.content.Context.BIND_IMPORTANT;
|
||||||
|
import static android.content.pm.PackageManager.MATCH_ALL;
|
||||||
|
|
||||||
|
import static com.android.internal.util.CollectionUtils.any;
|
||||||
import static com.android.internal.util.CollectionUtils.emptyIfNull;
|
import static com.android.internal.util.CollectionUtils.emptyIfNull;
|
||||||
|
import static com.android.internal.util.CollectionUtils.filter;
|
||||||
import static com.android.internal.util.CollectionUtils.find;
|
import static com.android.internal.util.CollectionUtils.find;
|
||||||
import static com.android.internal.util.CollectionUtils.forEach;
|
import static com.android.internal.util.CollectionUtils.forEach;
|
||||||
import static com.android.internal.util.CollectionUtils.map;
|
import static com.android.internal.util.CollectionUtils.map;
|
||||||
@@ -45,6 +48,7 @@ import android.app.PendingIntent;
|
|||||||
import android.app.role.RoleManager;
|
import android.app.role.RoleManager;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.le.BluetoothLeScanner;
|
||||||
import android.bluetooth.le.ScanCallback;
|
import android.bluetooth.le.ScanCallback;
|
||||||
import android.bluetooth.le.ScanFilter;
|
import android.bluetooth.le.ScanFilter;
|
||||||
import android.bluetooth.le.ScanResult;
|
import android.bluetooth.le.ScanResult;
|
||||||
@@ -58,15 +62,18 @@ import android.companion.ICompanionDeviceDiscoveryService;
|
|||||||
import android.companion.ICompanionDeviceManager;
|
import android.companion.ICompanionDeviceManager;
|
||||||
import android.companion.ICompanionDeviceService;
|
import android.companion.ICompanionDeviceService;
|
||||||
import android.companion.IFindDeviceCallback;
|
import android.companion.IFindDeviceCallback;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.FeatureInfo;
|
import android.content.pm.FeatureInfo;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageItemInfo;
|
import android.content.pm.PackageItemInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManagerInternal;
|
import android.content.pm.PackageManagerInternal;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.net.NetworkPolicyManager;
|
import android.net.NetworkPolicyManager;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
@@ -186,6 +193,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
|
|
||||||
private BluetoothDeviceConnectedListener mBluetoothDeviceConnectedListener =
|
private BluetoothDeviceConnectedListener mBluetoothDeviceConnectedListener =
|
||||||
new BluetoothDeviceConnectedListener();
|
new BluetoothDeviceConnectedListener();
|
||||||
|
private BleStateBroadcastReceiver mBleStateBroadcastReceiver = new BleStateBroadcastReceiver();
|
||||||
private List<String> mCurrentlyConnectedDevices = new ArrayList<>();
|
private List<String> mCurrentlyConnectedDevices = new ArrayList<>();
|
||||||
private ArrayMap<String, Date> mDevicesLastNearby = new ArrayMap<>();
|
private ArrayMap<String, Date> mDevicesLastNearby = new ArrayMap<>();
|
||||||
private UnbindDeviceListenersRunnable
|
private UnbindDeviceListenersRunnable
|
||||||
@@ -283,11 +291,14 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
@Override
|
@Override
|
||||||
public void onBootPhase(int phase) {
|
public void onBootPhase(int phase) {
|
||||||
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
|
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
|
||||||
|
// Init Bluetooth
|
||||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
if (mBluetoothAdapter != null) {
|
if (mBluetoothAdapter != null) {
|
||||||
mBluetoothAdapter.registerBluetoothConnectionCallback(
|
mBluetoothAdapter.registerBluetoothConnectionCallback(
|
||||||
getContext().getMainExecutor(),
|
getContext().getMainExecutor(),
|
||||||
mBluetoothDeviceConnectedListener);
|
mBluetoothDeviceConnectedListener);
|
||||||
|
getContext().registerReceiver(
|
||||||
|
mBleStateBroadcastReceiver, mBleStateBroadcastReceiver.mIntentFilter);
|
||||||
initBleScanning();
|
initBleScanning();
|
||||||
} else {
|
} else {
|
||||||
Log.w(LOG_TAG, "No BluetoothAdapter available");
|
Log.w(LOG_TAG, "No BluetoothAdapter available");
|
||||||
@@ -550,7 +561,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CollectionUtils.any(
|
return any(
|
||||||
getAllAssociations(userId, packageName),
|
getAllAssociations(userId, packageName),
|
||||||
a -> Objects.equals(a.getDeviceMacAddress(), macAddress));
|
a -> Objects.equals(a.getDeviceMacAddress(), macAddress));
|
||||||
}
|
}
|
||||||
@@ -902,7 +913,12 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<UserInfo> getAllUsers() {
|
private List<UserInfo> getAllUsers() {
|
||||||
return getContext().getSystemService(UserManager.class).getUsers();
|
long identity = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
return mUserManager.getUsers();
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -913,11 +929,16 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Set<Association> getAllAssociations() {
|
private Set<Association> getAllAssociations() {
|
||||||
ArraySet<Association> result = new ArraySet<>();
|
long identity = Binder.clearCallingIdentity();
|
||||||
for (UserInfo user : mUserManager.getAliveUsers()) {
|
try {
|
||||||
result.addAll(getAllAssociations(user.id));
|
ArraySet<Association> result = new ArraySet<>();
|
||||||
|
for (UserInfo user : mUserManager.getAliveUsers()) {
|
||||||
|
result.addAll(getAllAssociations(user.id));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Association> readAllAssociations(int userId) {
|
private Set<Association> readAllAssociations(int userId) {
|
||||||
@@ -1004,11 +1025,28 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
Association a) {
|
Association a) {
|
||||||
return mDeviceListenerServiceConnectors.forUser(a.getUserId()).computeIfAbsent(
|
return mDeviceListenerServiceConnectors.forUser(a.getUserId()).computeIfAbsent(
|
||||||
a.getPackageName(),
|
a.getPackageName(),
|
||||||
pkg -> new ServiceConnector.Impl<>(getContext(),
|
pkg -> createDeviceListenerServiceConnector(a));
|
||||||
new Intent(CompanionDeviceService.SERVICE_INTERFACE),
|
}
|
||||||
BIND_IMPORTANT,
|
|
||||||
a.getUserId(),
|
private ServiceConnector<ICompanionDeviceService> createDeviceListenerServiceConnector(
|
||||||
ICompanionDeviceService.Stub::asInterface));
|
Association a) {
|
||||||
|
List<ResolveInfo> resolveInfos = getContext().getPackageManager().queryIntentServicesAsUser(
|
||||||
|
new Intent(CompanionDeviceService.SERVICE_INTERFACE), MATCH_ALL, a.getUserId());
|
||||||
|
List<ResolveInfo> packageResolveInfos = filter(resolveInfos,
|
||||||
|
info -> Objects.equals(info.serviceInfo.packageName, a.getPackageName()));
|
||||||
|
if (packageResolveInfos.size() != 1) {
|
||||||
|
Log.w(LOG_TAG, "Device presence listener package must have exactly one "
|
||||||
|
+ "CompanionDeviceService, but " + a.getPackageName()
|
||||||
|
+ " has " + packageResolveInfos.size());
|
||||||
|
return new ServiceConnector.NoOp<>();
|
||||||
|
}
|
||||||
|
ComponentName componentName = packageResolveInfos.get(0).serviceInfo.getComponentName();
|
||||||
|
Log.i(LOG_TAG, "Initializing CompanionDeviceService binding for " + componentName);
|
||||||
|
return new ServiceConnector.Impl<>(getContext(),
|
||||||
|
new Intent(CompanionDeviceService.SERVICE_INTERFACE).setComponent(componentName),
|
||||||
|
BIND_IMPORTANT,
|
||||||
|
a.getUserId(),
|
||||||
|
ICompanionDeviceService.Stub::asInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BleScanCallback extends ScanCallback {
|
private class BleScanCallback extends ScanCallback {
|
||||||
@@ -1034,8 +1072,34 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
if (errorCode == SCAN_FAILED_ALREADY_STARTED) {
|
if (errorCode == SCAN_FAILED_ALREADY_STARTED) {
|
||||||
// ignore - this might happen if BT tries to auto-restore scans for us in the
|
// ignore - this might happen if BT tries to auto-restore scans for us in the
|
||||||
// future
|
// future
|
||||||
|
Log.i(LOG_TAG, "Ignoring BLE scan error: SCAN_FAILED_ALREADY_STARTED");
|
||||||
} else {
|
} else {
|
||||||
Log.wtf(LOG_TAG, "Failed to start BLE scan: error " + errorCode);
|
Log.w(LOG_TAG, "Failed to start BLE scan: error " + errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BleStateBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
final IntentFilter mIntentFilter =
|
||||||
|
new IntentFilter(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, -1);
|
||||||
|
int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
|
||||||
|
Log.i(LOG_TAG, "Received BT state transition broadcast: "
|
||||||
|
+ BluetoothAdapter.nameForState(previousState)
|
||||||
|
+ " -> " + BluetoothAdapter.nameForState(newState));
|
||||||
|
|
||||||
|
boolean bleOn = newState == BluetoothAdapter.STATE_ON
|
||||||
|
|| newState == BluetoothAdapter.STATE_BLE_ON;
|
||||||
|
if (bleOn) {
|
||||||
|
if (mBluetoothAdapter.getBluetoothLeScanner() != null) {
|
||||||
|
startBleScan();
|
||||||
|
} else {
|
||||||
|
Log.wtf(LOG_TAG, "BLE on, but BluetoothLeScanner == null");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1100,7 +1164,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
|
|
||||||
private void onDeviceNearby(String address) {
|
private void onDeviceNearby(String address) {
|
||||||
Date timestamp = new Date();
|
Date timestamp = new Date();
|
||||||
mDevicesLastNearby.put(address, timestamp);
|
Date oldTimestamp = mDevicesLastNearby.put(address, timestamp);
|
||||||
|
|
||||||
cancelUnbindDeviceListener(address);
|
cancelUnbindDeviceListener(address);
|
||||||
|
|
||||||
@@ -1108,15 +1172,20 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
.computeIfAbsent(address, addr -> new TriggerDeviceDisappearedRunnable(address))
|
.computeIfAbsent(address, addr -> new TriggerDeviceDisappearedRunnable(address))
|
||||||
.schedule();
|
.schedule();
|
||||||
|
|
||||||
for (Association association : getAllAssociations(address)) {
|
// Avoid spamming the app if device is already known to be nearby
|
||||||
if (association.isNotifyOnDeviceNearby()) {
|
boolean justAppeared = oldTimestamp == null
|
||||||
if (DEBUG) {
|
|| timestamp.getTime() - oldTimestamp.getTime() >= DEVICE_DISAPPEARED_TIMEOUT_MS;
|
||||||
Log.i(LOG_TAG, "Device " + address
|
if (justAppeared) {
|
||||||
+ " managed by " + association.getPackageName()
|
for (Association association : getAllAssociations(address)) {
|
||||||
+ " is nearby on " + timestamp);
|
if (association.isNotifyOnDeviceNearby()) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.i(LOG_TAG, "Device " + address
|
||||||
|
+ " managed by " + association.getPackageName()
|
||||||
|
+ " is nearby on " + timestamp);
|
||||||
|
}
|
||||||
|
getDeviceListenerServiceConnector(association).run(
|
||||||
|
service -> service.onDeviceAppeared(association.getDeviceMacAddress()));
|
||||||
}
|
}
|
||||||
getDeviceListenerServiceConnector(association).run(
|
|
||||||
service -> service.onDeviceAppeared(association.getDeviceMacAddress()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1152,6 +1221,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initBleScanning() {
|
private void initBleScanning() {
|
||||||
|
Log.i(LOG_TAG, "initBleScanning()");
|
||||||
|
|
||||||
boolean bluetoothReady = mBluetoothAdapter.registerServiceLifecycleCallback(
|
boolean bluetoothReady = mBluetoothAdapter.registerServiceLifecycleCallback(
|
||||||
new BluetoothAdapter.ServiceLifecycleCallback() {
|
new BluetoothAdapter.ServiceLifecycleCallback() {
|
||||||
@Override
|
@Override
|
||||||
@@ -1171,14 +1242,21 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
|||||||
}
|
}
|
||||||
|
|
||||||
void startBleScan() {
|
void startBleScan() {
|
||||||
|
Log.i(LOG_TAG, "startBleScan()");
|
||||||
|
|
||||||
List<ScanFilter> filters = getBleScanFilters();
|
List<ScanFilter> filters = getBleScanFilters();
|
||||||
if (filters.isEmpty()) {
|
if (filters.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mBluetoothAdapter.getBluetoothLeScanner().startScan(
|
BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
|
||||||
filters,
|
if (scanner == null) {
|
||||||
new ScanSettings.Builder().setScanMode(SCAN_MODE_BALANCED).build(),
|
Log.w(LOG_TAG, "scanner == null (likely BLE isn't ON yet)");
|
||||||
mBleScanCallback);
|
} else {
|
||||||
|
scanner.startScan(
|
||||||
|
filters,
|
||||||
|
new ScanSettings.Builder().setScanMode(SCAN_MODE_BALANCED).build(),
|
||||||
|
mBleScanCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void restartBleScan() {
|
void restartBleScan() {
|
||||||
|
|||||||
Reference in New Issue
Block a user