From 22ca72a67534a292ca81cbd43311b9e1bcfa1155 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 3 Jun 2021 09:26:53 -0600 Subject: [PATCH] More Binder call AttributionSource assignment. Since developers can use a BluetoothDevice object can make remote calls, it needs to have an accurate AttributionSource. Previous CLs had updated many places where these BluetoothDevice instances were passed across Binder interfaces, but this change updates several remaining locations which had been missed. Introduces new "Attributable" marker interface to offer consistent tooling when applying AttributionSource updates. Bug: 187097694 Test: atest BluetoothInstrumentationTests Change-Id: Icad3b9726591f0fbad58a493cefa5a0af7648280 --- .../java/android/bluetooth/BluetoothA2dp.java | 15 +++-- .../android/bluetooth/BluetoothA2dpSink.java | 5 +- .../android/bluetooth/BluetoothAdapter.java | 58 +++++++++++-------- .../bluetooth/BluetoothAvrcpController.java | 5 +- .../android/bluetooth/BluetoothDevice.java | 25 ++------ .../android/bluetooth/BluetoothHeadset.java | 11 ++-- .../bluetooth/BluetoothHeadsetClient.java | 11 ++-- .../bluetooth/BluetoothHeadsetClientCall.java | 10 +++- .../bluetooth/BluetoothHearingAid.java | 8 ++- .../android/bluetooth/BluetoothHidDevice.java | 21 +++++-- .../android/bluetooth/BluetoothHidHost.java | 5 +- .../android/bluetooth/BluetoothLeAudio.java | 8 ++- .../android/bluetooth/BluetoothManager.java | 7 ++- core/java/android/bluetooth/BluetoothMap.java | 8 ++- .../android/bluetooth/BluetoothMapClient.java | 5 +- core/java/android/bluetooth/BluetoothPan.java | 5 +- .../java/android/bluetooth/BluetoothPbap.java | 5 +- .../bluetooth/BluetoothPbapClient.java | 5 +- core/java/android/bluetooth/BluetoothSap.java | 8 ++- .../bluetooth/le/BluetoothLeScanner.java | 4 ++ .../le/PeriodicAdvertisingManager.java | 3 +- .../java/android/bluetooth/le/ScanResult.java | 10 +++- core/java/android/content/Attributable.java | 54 +++++++++++++++++ 23 files changed, 201 insertions(+), 95 deletions(-) create mode 100644 core/java/android/content/Attributable.java diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 1fb7638a6f057..65cdca9eb7d86 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -29,6 +29,7 @@ import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -389,8 +390,9 @@ public final class BluetoothA2dp implements BluetoothProfile { try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled()) { - return BluetoothDevice.setAttributionSource( - service.getConnectedDevices(), mAttributionSource); + return Attributable.setAttributionSource( + service.getConnectedDevicesWithAttribution(mAttributionSource), + mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return new ArrayList(); @@ -411,8 +413,10 @@ public final class BluetoothA2dp implements BluetoothProfile { try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled()) { - return BluetoothDevice.setAttributionSource( - service.getDevicesMatchingConnectionStates(states), mAttributionSource); + return Attributable.setAttributionSource( + service.getDevicesMatchingConnectionStatesWithAttribution(states, + mAttributionSource), + mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return new ArrayList(); @@ -500,7 +504,8 @@ public final class BluetoothA2dp implements BluetoothProfile { try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled()) { - return service.getActiveDevice(mAttributionSource); + return Attributable.setAttributionSource( + service.getActiveDevice(mAttributionSource), mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return null; diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java index c0a2aa3db4211..2dd63a0263fe4 100755 --- a/core/java/android/bluetooth/BluetoothA2dpSink.java +++ b/core/java/android/bluetooth/BluetoothA2dpSink.java @@ -27,6 +27,7 @@ import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -206,7 +207,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile { final IBluetoothA2dpSink service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); @@ -230,7 +231,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile { final IBluetoothA2dpSink service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 54941724b2f75..054b63fbad507 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -46,6 +46,7 @@ import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.BatteryStats; @@ -719,8 +720,8 @@ public final class BluetoothAdapter { private final Object mLock = new Object(); private final Map mLeScanClients; - private static final Map>> - sMetadataListeners = new HashMap<>(); + private final Map>> + mMetadataListeners = new HashMap<>(); private final Map mBluetoothConnectionCallbackExecutorMap = new HashMap<>(); @@ -729,14 +730,15 @@ public final class BluetoothAdapter { * implementation. */ @SuppressLint("AndroidFrameworkBluetoothPermission") - private static final IBluetoothMetadataListener sBluetoothMetadataListener = + private final IBluetoothMetadataListener mBluetoothMetadataListener = new IBluetoothMetadataListener.Stub() { @Override public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) { - synchronized (sMetadataListeners) { - if (sMetadataListeners.containsKey(device)) { + Attributable.setAttributionSource(device, mAttributionSource); + synchronized (mMetadataListeners) { + if (mMetadataListeners.containsKey(device)) { List> list = - sMetadataListeners.get(device); + mMetadataListeners.get(device); for (Pair pair : list) { OnMetadataChangedListener listener = pair.first; Executor executor = pair.second; @@ -2445,7 +2447,9 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getMostRecentlyConnectedDevices(mAttributionSource); + return Attributable.setAttributionSource( + mService.getMostRecentlyConnectedDevices(mAttributionSource), + mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2470,14 +2474,16 @@ public final class BluetoothAdapter { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public Set getBondedDevices() { if (getState() != STATE_ON) { - return toDeviceSet(new BluetoothDevice[0]); + return toDeviceSet(Arrays.asList()); } try { mServiceLock.readLock().lock(); if (mService != null) { - return toDeviceSet(mService.getBondedDevices(mAttributionSource)); + return toDeviceSet(Attributable.setAttributionSource( + Arrays.asList(mService.getBondedDevices(mAttributionSource)), + mAttributionSource)); } - return toDeviceSet(new BluetoothDevice[0]); + return toDeviceSet(Arrays.asList()); } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -3165,10 +3171,10 @@ public final class BluetoothAdapter { } } } - synchronized (sMetadataListeners) { - sMetadataListeners.forEach((device, pair) -> { + synchronized (mMetadataListeners) { + mMetadataListeners.forEach((device, pair) -> { try { - mService.registerMetadataListener(sBluetoothMetadataListener, + mService.registerMetadataListener(mBluetoothMetadataListener, device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Failed to register metadata listener", e); @@ -3455,8 +3461,8 @@ public final class BluetoothAdapter { } } - private Set toDeviceSet(BluetoothDevice[] devices) { - Set deviceSet = new HashSet(Arrays.asList(devices)); + private Set toDeviceSet(List devices) { + Set deviceSet = new HashSet(devices); return Collections.unmodifiableSet(deviceSet); } @@ -3926,13 +3932,13 @@ public final class BluetoothAdapter { throw new NullPointerException("executor is null"); } - synchronized (sMetadataListeners) { + synchronized (mMetadataListeners) { List> listenerList = - sMetadataListeners.get(device); + mMetadataListeners.get(device); if (listenerList == null) { // Create new listener/executor list for registeration listenerList = new ArrayList<>(); - sMetadataListeners.put(device, listenerList); + mMetadataListeners.put(device, listenerList); } else { // Check whether this device was already registed by the lisenter if (listenerList.stream().anyMatch((pair) -> (pair.first.equals(listener)))) { @@ -3946,7 +3952,7 @@ public final class BluetoothAdapter { boolean ret = false; try { - ret = service.registerMetadataListener(sBluetoothMetadataListener, device, + ret = service.registerMetadataListener(mBluetoothMetadataListener, device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "registerMetadataListener fail", e); @@ -3956,7 +3962,7 @@ public final class BluetoothAdapter { listenerList.remove(listenerPair); if (listenerList.isEmpty()) { // Remove the device if its listener list is empty - sMetadataListeners.remove(device); + mMetadataListeners.remove(device); } } } @@ -3995,17 +4001,17 @@ public final class BluetoothAdapter { throw new NullPointerException("listener is null"); } - synchronized (sMetadataListeners) { - if (!sMetadataListeners.containsKey(device)) { + synchronized (mMetadataListeners) { + if (!mMetadataListeners.containsKey(device)) { throw new IllegalArgumentException("device was not registered"); } // Remove issued listener from the registered device - sMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener))); + mMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener))); - if (sMetadataListeners.get(device).isEmpty()) { + if (mMetadataListeners.get(device).isEmpty()) { // Unregister to Bluetooth service if all listeners are removed from // the registered device - sMetadataListeners.remove(device); + mMetadataListeners.remove(device); final IBluetooth service = mService; if (service == null) { // Bluetooth is OFF, do nothing to Bluetooth service. @@ -4045,6 +4051,7 @@ public final class BluetoothAdapter { new IBluetoothConnectionCallback.Stub() { @Override public void onDeviceConnected(BluetoothDevice device) { + Attributable.setAttributionSource(device, mAttributionSource); for (Map.Entry callbackExecutorEntry: mBluetoothConnectionCallbackExecutorMap.entrySet()) { BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); @@ -4055,6 +4062,7 @@ public final class BluetoothAdapter { @Override public void onDeviceDisconnected(BluetoothDevice device, int hciReason) { + Attributable.setAttributionSource(device, mAttributionSource); for (Map.Entry callbackExecutorEntry: mBluetoothConnectionCallbackExecutorMap.entrySet()) { BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java index 0b43e71aba2ac..d27c27648008e 100644 --- a/core/java/android/bluetooth/BluetoothAvrcpController.java +++ b/core/java/android/bluetooth/BluetoothAvrcpController.java @@ -22,6 +22,7 @@ import android.annotation.SuppressLint; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -135,7 +136,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); @@ -158,7 +159,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index f2496fe0cac2e..21ec91865d0a5 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -32,6 +32,7 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.companion.AssociationRequest; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Build; @@ -47,7 +48,6 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.List; import java.util.UUID; /** @@ -84,7 +84,7 @@ import java.util.UUID; * {@see BluetoothAdapter} * {@see BluetoothSocket} */ -public final class BluetoothDevice implements Parcelable { +public final class BluetoothDevice implements Parcelable, Attributable { private static final String TAG = "BluetoothDevice"; private static final boolean DBG = false; @@ -1170,28 +1170,13 @@ public final class BluetoothDevice implements Parcelable { mAttributionSource = BluetoothManager.resolveAttributionSource(null); } - void setAttributionSource(AttributionSource attributionSource) { + /** {@hide} */ + public void setAttributionSource(@NonNull AttributionSource attributionSource) { mAttributionSource = attributionSource; } - static BluetoothDevice setAttributionSource(BluetoothDevice device, - AttributionSource attributionSource) { - device.setAttributionSource(attributionSource); - return device; - } - - static List setAttributionSource(List devices, - AttributionSource attributionSource) { - if (devices != null) { - for (BluetoothDevice device : devices) { - device.setAttributionSource(attributionSource); - } - } - return devices; - } - /** {@hide} */ - public void prepareToEnterProcess(AttributionSource attributionSource) { + public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) { setAttributionSource(attributionSource); } diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 3bf517c046f35..42b9a8d2e35a0 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -28,6 +28,7 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.ComponentName; import android.content.Context; @@ -532,8 +533,9 @@ public final class BluetoothHeadset implements BluetoothProfile { final IBluetoothHeadset service = mService; if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( - service.getConnectedDevices(), mAttributionSource); + return Attributable.setAttributionSource( + service.getConnectedDevicesWithAttribution(mAttributionSource), + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); return new ArrayList(); @@ -554,7 +556,7 @@ public final class BluetoothHeadset implements BluetoothProfile { final IBluetoothHeadset service = mService; if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { @@ -1310,7 +1312,8 @@ public final class BluetoothHeadset implements BluetoothProfile { final IBluetoothHeadset service = mService; if (service != null && isEnabled()) { try { - return service.getActiveDevice(mAttributionSource); + return Attributable.setAttributionSource( + service.getActiveDevice(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); } diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java index 0059cdb9fbb7b..83108d22e0c3f 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClient.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java @@ -23,6 +23,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -535,7 +536,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -562,7 +563,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { @@ -797,7 +798,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { getService(); if (service != null && isEnabled() && isValidDevice(device)) { try { - return service.getCurrentCalls(device, mAttributionSource); + return Attributable.setAttributionSource( + service.getCurrentCalls(device, mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); } @@ -1020,7 +1022,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { getService(); if (service != null && isEnabled() && isValidDevice(device)) { try { - return service.dial(device, number, mAttributionSource); + return Attributable.setAttributionSource( + service.dial(device, number, mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); } diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java index 219d1596fbf3b..3f1ef84612509 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java @@ -16,7 +16,10 @@ package android.bluetooth; +import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; +import android.content.AttributionSource; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -30,7 +33,7 @@ import java.util.UUID; * * @hide */ -public final class BluetoothHeadsetClientCall implements Parcelable { +public final class BluetoothHeadsetClientCall implements Parcelable, Attributable { /* Call state */ /** @@ -98,6 +101,11 @@ public final class BluetoothHeadsetClientCall implements Parcelable { mCreationElapsedMilli = SystemClock.elapsedRealtime(); } + /** {@hide} */ + public void setAttributionSource(@NonNull AttributionSource attributionSource) { + Attributable.setAttributionSource(mDevice, attributionSource); + } + /** * Sets call's state. * diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java index 3ff2ebd86b6e8..183f4d55bde55 100644 --- a/core/java/android/bluetooth/BluetoothHearingAid.java +++ b/core/java/android/bluetooth/BluetoothHearingAid.java @@ -28,6 +28,7 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -248,7 +249,7 @@ public final class BluetoothHearingAid implements BluetoothProfile { final IBluetoothHearingAid service = getService(); try { if (service != null && isEnabled()) { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); @@ -271,7 +272,7 @@ public final class BluetoothHearingAid implements BluetoothProfile { final IBluetoothHearingAid service = getService(); try { if (service != null && isEnabled()) { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } @@ -363,7 +364,8 @@ public final class BluetoothHearingAid implements BluetoothProfile { final IBluetoothHearingAid service = getService(); try { if (service != null && isEnabled()) { - return service.getActiveDevices(mAttributionSource); + return Attributable.setAttributionSource( + service.getActiveDevices(mAttributionSource), mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return new ArrayList<>(); diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java index 11e5711eff1aa..c2744b89aadc8 100644 --- a/core/java/android/bluetooth/BluetoothHidDevice.java +++ b/core/java/android/bluetooth/BluetoothHidDevice.java @@ -20,11 +20,11 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; -import android.annotation.SuppressLint; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; -import android.annotation.SystemApi; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -339,14 +339,17 @@ public final class BluetoothHidDevice implements BluetoothProfile { private final Executor mExecutor; private final Callback mCallback; + private final AttributionSource mAttributionSource; - CallbackWrapper(Executor executor, Callback callback) { + CallbackWrapper(Executor executor, Callback callback, AttributionSource attributionSource) { mExecutor = executor; mCallback = callback; + mAttributionSource = attributionSource; } @Override public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) { + Attributable.setAttributionSource(pluggedDevice, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onAppStatusChanged(pluggedDevice, registered)); @@ -357,6 +360,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onConnectionStateChanged(BluetoothDevice device, int state) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onConnectionStateChanged(device, state)); @@ -367,6 +371,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onGetReport(device, type, id, bufferSize)); @@ -377,6 +382,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onSetReport(device, type, id, data)); @@ -387,6 +393,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onSetProtocol(BluetoothDevice device, byte protocol) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onSetProtocol(device, protocol)); @@ -397,6 +404,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onInterruptData(device, reportId, data)); @@ -407,6 +415,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { @Override public void onVirtualCableUnplug(BluetoothDevice device) { + Attributable.setAttributionSource(device, mAttributionSource); final long token = clearCallingIdentity(); try { mExecutor.execute(() -> mCallback.onVirtualCableUnplug(device)); @@ -449,7 +458,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { final IBluetoothHidDevice service = getService(); if (service != null) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString()); @@ -469,7 +478,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { final IBluetoothHidDevice service = getService(); if (service != null) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { @@ -549,7 +558,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { final IBluetoothHidDevice service = getService(); if (service != null) { try { - CallbackWrapper cbw = new CallbackWrapper(executor, callback); + CallbackWrapper cbw = new CallbackWrapper(executor, callback, mAttributionSource); result = service.registerApp(sdp, inQos, outQos, cbw, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString()); diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java index 0abe18c4d2201..fb4cbb2eb134b 100644 --- a/core/java/android/bluetooth/BluetoothHidHost.java +++ b/core/java/android/bluetooth/BluetoothHidHost.java @@ -26,6 +26,7 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -360,7 +361,7 @@ public final class BluetoothHidHost implements BluetoothProfile { final IBluetoothHidHost service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); @@ -384,7 +385,7 @@ public final class BluetoothHidHost implements BluetoothProfile { final IBluetoothHidHost service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java index 51bfd048fdc49..9de27ff97fe54 100644 --- a/core/java/android/bluetooth/BluetoothLeAudio.java +++ b/core/java/android/bluetooth/BluetoothLeAudio.java @@ -26,6 +26,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -227,7 +228,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { try { final IBluetoothLeAudio service = getService(); if (service != null && mAdapter.isEnabled()) { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); @@ -250,7 +251,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { try { final IBluetoothLeAudio service = getService(); if (service != null && mAdapter.isEnabled()) { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } @@ -339,7 +340,8 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { try { final IBluetoothLeAudio service = getService(); if (service != null && mAdapter.isEnabled()) { - return service.getActiveDevices(mAttributionSource); + return Attributable.setAttributionSource( + service.getActiveDevices(mAttributionSource), mAttributionSource); } if (service == null) Log.w(TAG, "Proxy not attached to service"); return new ArrayList<>(); diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java index b13ccaf7e570f..c21362cd89f91 100644 --- a/core/java/android/bluetooth/BluetoothManager.java +++ b/core/java/android/bluetooth/BluetoothManager.java @@ -16,6 +16,8 @@ package android.bluetooth; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresNoPermission; import android.annotation.RequiresPermission; @@ -24,6 +26,7 @@ import android.app.ActivityThread; import android.app.AppGlobals; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.content.pm.PackageManager; @@ -71,7 +74,7 @@ public final class BluetoothManager { } /** {@hide} */ - public static AttributionSource resolveAttributionSource(Context context) { + public static @NonNull AttributionSource resolveAttributionSource(@Nullable Context context) { AttributionSource res = null; if (context != null) { res = context.getAttributionSource(); @@ -193,7 +196,7 @@ public final class BluetoothManager { IBluetoothManager managerService = mAdapter.getBluetoothManager(); IBluetoothGatt iGatt = managerService.getBluetoothGatt(); if (iGatt == null) return devices; - devices = BluetoothDevice.setAttributionSource( + devices = Attributable.setAttributionSource( iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java index 88505b51f8311..86796519df4cf 100644 --- a/core/java/android/bluetooth/BluetoothMap.java +++ b/core/java/android/bluetooth/BluetoothMap.java @@ -26,6 +26,7 @@ import android.annotation.SystemApi; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -170,7 +171,8 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { final IBluetoothMap service = getService(); if (service != null) { try { - return service.getClient(mAttributionSource); + return Attributable.setAttributionSource( + service.getClient(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString()); } @@ -285,7 +287,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { final IBluetoothMap service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -310,7 +312,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { final IBluetoothMap service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java index 14804dbefeb68..042b58669a066 100644 --- a/core/java/android/bluetooth/BluetoothMapClient.java +++ b/core/java/android/bluetooth/BluetoothMapClient.java @@ -26,6 +26,7 @@ import android.annotation.SystemApi; import android.app.PendingIntent; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.net.Uri; @@ -302,7 +303,7 @@ public final class BluetoothMapClient implements BluetoothProfile { final IBluetoothMapClient service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -327,7 +328,7 @@ public final class BluetoothMapClient implements BluetoothProfile { final IBluetoothMapClient service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index d1f34cbe0371a..577be3d2aea4b 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -27,6 +27,7 @@ import android.annotation.SystemApi; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -357,7 +358,7 @@ public final class BluetoothPan implements BluetoothProfile { final IBluetoothPan service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); @@ -384,7 +385,7 @@ public final class BluetoothPan implements BluetoothProfile { final IBluetoothPan service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java index 8ce01a37cdde0..c000e56e7b04e 100644 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ b/core/java/android/bluetooth/BluetoothPbap.java @@ -25,6 +25,7 @@ import android.annotation.SystemApi; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.ComponentName; import android.content.Context; @@ -243,7 +244,7 @@ public class BluetoothPbap implements BluetoothProfile { return new ArrayList(); } try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString()); @@ -296,7 +297,7 @@ public class BluetoothPbap implements BluetoothProfile { return new ArrayList(); } try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java index 3ebd8fe19205e..c7dd6bd9af148 100644 --- a/core/java/android/bluetooth/BluetoothPbapClient.java +++ b/core/java/android/bluetooth/BluetoothPbapClient.java @@ -23,6 +23,7 @@ import android.annotation.SdkConstant; import android.annotation.SuppressLint; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -187,7 +188,7 @@ public final class BluetoothPbapClient implements BluetoothProfile { final IBluetoothPbapClient service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -215,7 +216,7 @@ public final class BluetoothPbapClient implements BluetoothProfile { final IBluetoothPbapClient service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java index 0631abdadac9f..fda19ed6d0cc2 100644 --- a/core/java/android/bluetooth/BluetoothSap.java +++ b/core/java/android/bluetooth/BluetoothSap.java @@ -24,6 +24,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; @@ -182,7 +183,8 @@ public final class BluetoothSap implements BluetoothProfile { final IBluetoothSap service = getService(); if (service != null) { try { - return service.getClient(mAttributionSource); + return Attributable.setAttributionSource( + service.getClient(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString()); } @@ -268,7 +270,7 @@ public final class BluetoothSap implements BluetoothProfile { final IBluetoothSap service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getConnectedDevices(mAttributionSource), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); @@ -292,7 +294,7 @@ public final class BluetoothSap implements BluetoothProfile { final IBluetoothSap service = getService(); if (service != null && isEnabled()) { try { - return BluetoothDevice.setAttributionSource( + return Attributable.setAttributionSource( service.getDevicesMatchingConnectionStates(states, mAttributionSource), mAttributionSource); } catch (RemoteException e) { diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index 60d4e2d6d2d3e..34aac8bfdb25e 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -30,6 +30,7 @@ import android.bluetooth.IBluetoothManager; import android.bluetooth.annotations.RequiresBluetoothLocationPermission; import android.bluetooth.annotations.RequiresBluetoothScanPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.os.Handler; import android.os.Looper; @@ -516,6 +517,7 @@ public final class BluetoothLeScanner { */ @Override public void onScanResult(final ScanResult scanResult) { + Attributable.setAttributionSource(scanResult, mAttributionSource); if (VDBG) Log.d(TAG, "onScanResult() - " + scanResult.toString()); // Check null in case the scan has been stopped @@ -533,6 +535,7 @@ public final class BluetoothLeScanner { @Override public void onBatchScanResults(final List results) { + Attributable.setAttributionSource(results, mAttributionSource); Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override @@ -544,6 +547,7 @@ public final class BluetoothLeScanner { @Override public void onFoundOrLost(final boolean onFound, final ScanResult scanResult) { + Attributable.setAttributionSource(scanResult, mAttributionSource); if (VDBG) { Log.d(TAG, "onFoundOrLost() - onFound = " + onFound + " " + scanResult.toString()); } diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java index 47f47bb8e3635..dea686d18ea2e 100644 --- a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java +++ b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java @@ -25,6 +25,7 @@ import android.bluetooth.IBluetoothManager; import android.bluetooth.annotations.RequiresBluetoothLocationPermission; import android.bluetooth.annotations.RequiresBluetoothScanPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; +import android.content.Attributable; import android.content.AttributionSource; import android.os.Handler; import android.os.Looper; @@ -220,7 +221,7 @@ public final class PeriodicAdvertisingManager { return new IPeriodicAdvertisingCallback.Stub() { public void onSyncEstablished(int syncHandle, BluetoothDevice device, int advertisingSid, int skip, int timeout, int status) { - + Attributable.setAttributionSource(device, mAttributionSource); handler.post(new Runnable() { @Override public void run() { diff --git a/core/java/android/bluetooth/le/ScanResult.java b/core/java/android/bluetooth/le/ScanResult.java index 57dad1a0259b0..5228456284878 100644 --- a/core/java/android/bluetooth/le/ScanResult.java +++ b/core/java/android/bluetooth/le/ScanResult.java @@ -16,8 +16,11 @@ package android.bluetooth.le; +import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothDevice; +import android.content.Attributable; +import android.content.AttributionSource; import android.os.Parcel; import android.os.Parcelable; @@ -26,7 +29,7 @@ import java.util.Objects; /** * ScanResult for Bluetooth LE scan. */ -public final class ScanResult implements Parcelable { +public final class ScanResult implements Parcelable, Attributable { /** * For chained advertisements, inidcates tha the data contained in this @@ -195,6 +198,11 @@ public final class ScanResult implements Parcelable { return 0; } + /** {@hide} */ + public void setAttributionSource(@NonNull AttributionSource attributionSource) { + Attributable.setAttributionSource(mDevice, attributionSource); + } + /** * Returns the remote Bluetooth device identified by the Bluetooth device address. */ diff --git a/core/java/android/content/Attributable.java b/core/java/android/content/Attributable.java new file mode 100644 index 0000000000000..ce0c227e0cb55 --- /dev/null +++ b/core/java/android/content/Attributable.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 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.content; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.util.List; + +/** + * Marker interface for a class which can have an {@link AttributionSource} + * assigned to it; these are typically {@link android.os.Parcelable} classes + * which need to be updated after crossing Binder transaction boundaries. + * + * @hide + */ +public interface Attributable { + void setAttributionSource(@NonNull AttributionSource attributionSource); + + static @Nullable T setAttributionSource( + @Nullable T attributable, + @NonNull AttributionSource attributionSource) { + if (attributable != null) { + attributable.setAttributionSource(attributionSource); + } + return attributable; + } + + static @Nullable List setAttributionSource( + @Nullable List attributableList, + @NonNull AttributionSource attributionSource) { + if (attributableList != null) { + final int size = attributableList.size(); + for (int i = 0; i < size; i++) { + setAttributionSource(attributableList.get(i), attributionSource); + } + } + return attributableList; + } +}