From 25fc56ed6a3506d3c83cd01803a3b34e5ffff4ca Mon Sep 17 00:00:00 2001 From: William Escande Date: Fri, 22 Apr 2022 15:49:39 -0700 Subject: Add caching for {Map,Sap}.getConnectionState BluetoothMap and BluetoothSap are heavily using their getConnectionState method. By caching the value I intend to reduce drastically the number of binder calls generated. While performing a discovery, the caching is working on 80% of binder calls. This value should be bigger when we kepp asking the value for the same device. (currently everytime you ask the connection state of a new device, you refresh the cache, there is no caching for multiples devices). I don't have any Map/Sap setup to test it, asking to test team if they hit some issues Fixing cache on BluetoothDevice by passing the device as parameter Doing a refactoring of all cached method in bluetooth to keep code consistency: AKA we try to do the most of check outside of the cache query Bug: 217366135 Test: Put some log to see the value being cached sometimes - need more testing Ignore-AOSP-First: No caching api on AOSP Change-Id: Iababf9f9068a181e277b400e786a4a67d4447dc8 --- .../java/android/bluetooth/BluetoothAdapter.java | 218 ++++++++++++--------- 1 file changed, 121 insertions(+), 97 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 51239f1236..eed12635c5 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1269,36 +1269,27 @@ public final class BluetoothAdapter { IpcDataCache.invalidateCache(IpcDataCache.MODULE_BLUETOOTH, api); } - /** - * The binder cache for getState(). - */ - private static final String GET_STATE_API = "getState"; - - private final IpcDataCache.QueryHandler mBluetoothGetStateQuery = + private final IpcDataCache.QueryHandler mBluetoothGetStateQuery = new IpcDataCache.QueryHandler<>() { - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - @Override - public @InternalAdapterState Integer apply(Void query) { - int state = BluetoothAdapter.STATE_OFF; - mServiceLock.readLock().lock(); - try { - if (mService != null) { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - mService.getState(recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(state); + @RequiresLegacyBluetoothPermission + @RequiresNoPermission + @Override + public @InternalAdapterState Integer apply(IBluetooth serviceQuery) { + try { + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + serviceQuery.getState(recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()) + .getValue(BluetoothAdapter.STATE_OFF); + } catch (RemoteException | TimeoutException e) { + throw new RuntimeException(e); } - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } finally { - mServiceLock.readLock().unlock(); } - return state; - }}; + }; - private final IpcDataCache mBluetoothGetStateCache = - new BluetoothCache(GET_STATE_API, mBluetoothGetStateQuery); + private static final String GET_STATE_API = "BluetoothAdapter_getState"; + + private final IpcDataCache mBluetoothGetStateCache = + new BluetoothCache<>(GET_STATE_API, mBluetoothGetStateQuery); /** @hide */ @RequiresNoPermission @@ -1316,7 +1307,21 @@ public final class BluetoothAdapter { * OFF. */ private @InternalAdapterState int getStateInternal() { - return mBluetoothGetStateCache.query(null); + mServiceLock.readLock().lock(); + try { + if (mService != null) { + return mBluetoothGetStateCache.query(mService); + } + } catch (RuntimeException e) { + if (!(e.getCause() instanceof TimeoutException) + && !(e.getCause() instanceof RemoteException)) { + throw e; + } + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } finally { + mServiceLock.readLock().unlock(); + } + return STATE_OFF; } /** @@ -2417,31 +2422,25 @@ public final class BluetoothAdapter { } } - private final IpcDataCache.QueryHandler mBluetoothFilteringQuery = + private final IpcDataCache.QueryHandler mBluetoothFilteringQuery = new IpcDataCache.QueryHandler<>() { @RequiresLegacyBluetoothPermission @RequiresNoPermission @Override - public Boolean apply(Void query) { - mServiceLock.readLock().lock(); + public Boolean apply(IBluetooth serviceQuery) { try { - if (mService != null) { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - mService.isOffloadedFilteringSupported(recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false); - } + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + serviceQuery.isOffloadedFilteringSupported(recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false); } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } finally { - mServiceLock.readLock().unlock(); + throw new RuntimeException(e); } - return false; }}; - private static final String FILTERING_API = "isOffloadedFilteringSupported"; + private static final String FILTERING_API = "BluetoothAdapter_isOffloadedFilteringSupported"; - private final IpcDataCache mBluetoothFilteringCache = - new BluetoothCache(FILTERING_API, mBluetoothFilteringQuery); + private final IpcDataCache mBluetoothFilteringCache = + new BluetoothCache<>(FILTERING_API, mBluetoothFilteringQuery); /** @hide */ @RequiresNoPermission @@ -2465,7 +2464,19 @@ public final class BluetoothAdapter { if (!getLeAccess()) { return false; } - return mBluetoothFilteringCache.query(null); + mServiceLock.readLock().lock(); + try { + if (mService != null) return mBluetoothFilteringCache.query(mService); + } catch (RuntimeException e) { + if (!(e.getCause() instanceof TimeoutException) + && !(e.getCause() instanceof RemoteException)) { + throw e; + } + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } finally { + mServiceLock.readLock().unlock(); + } + return false; } /** @@ -2967,35 +2978,28 @@ public final class BluetoothAdapter { return supportedProfiles; } - private final IpcDataCache.QueryHandler mBluetoothGetAdapterQuery = - new IpcDataCache.QueryHandler<>() { - @RequiresLegacyBluetoothPermission - @RequiresNoPermission - @Override - public Integer apply(Void query) { - mServiceLock.readLock().lock(); - try { - if (mService != null) { - final SynchronousResultReceiver recv = - new SynchronousResultReceiver(); - mService.getAdapterConnectionState(recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()) + private final IpcDataCache.QueryHandler + mBluetoothGetAdapterConnectionStateQuery = new IpcDataCache.QueryHandler<>() { + @RequiresLegacyBluetoothPermission + @RequiresNoPermission + @Override + public Integer apply(IBluetooth serviceQuery) { + try { + final SynchronousResultReceiver recv = + new SynchronousResultReceiver(); + serviceQuery.getAdapterConnectionState(recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()) .getValue(STATE_DISCONNECTED); + } catch (RemoteException | TimeoutException e) { + throw new RuntimeException(e); + } } - } catch (TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } catch (RemoteException e) { - Log.e(TAG, "failed to getConnectionState, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return BluetoothAdapter.STATE_DISCONNECTED; - }}; + }; + + private static final String GET_CONNECTION_API = "BluetoothAdapter_getConnectionState"; - private static final String GET_CONNECTION_API = "getAdapterConnectionState"; - private final IpcDataCache - mBluetoothGetAdapterConnectionStateCache = - new BluetoothCache(GET_CONNECTION_API, mBluetoothGetAdapterQuery); + private final IpcDataCache mBluetoothGetAdapterConnectionStateCache = + new BluetoothCache<>(GET_CONNECTION_API, mBluetoothGetAdapterConnectionStateQuery); /** @hide */ @RequiresNoPermission @@ -3025,36 +3029,42 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) { return BluetoothAdapter.STATE_DISCONNECTED; } - return mBluetoothGetAdapterConnectionStateCache.query(null); + mServiceLock.readLock().lock(); + try { + if (mService != null) return mBluetoothGetAdapterConnectionStateCache.query(mService); + } catch (RuntimeException e) { + if (!(e.getCause() instanceof TimeoutException) + && !(e.getCause() instanceof RemoteException)) { + throw e; + } + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } finally { + mServiceLock.readLock().unlock(); + } + return STATE_DISCONNECTED; } - private final IpcDataCache.QueryHandler mBluetoothProfileQuery = - new IpcDataCache.QueryHandler<>() { - @RequiresNoPermission - @Override - public Integer apply(Integer query) { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - mService.getProfileConnectionState(query, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()) - .getValue(BluetoothProfile.STATE_DISCONNECTED); + private final IpcDataCache.QueryHandler, Integer> + mBluetoothProfileQuery = new IpcDataCache.QueryHandler<>() { + @RequiresNoPermission + @Override + public Integer apply(Pair pairQuery) { + final int defaultValue = STATE_DISCONNECTED; + try { + final SynchronousResultReceiver recv = + new SynchronousResultReceiver(); + pairQuery.first.getProfileConnectionState(pairQuery.second, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + throw new RuntimeException(e); + } } - } catch (TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } catch (RemoteException e) { - Log.e(TAG, "failed to getProfileConnectionState, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return BluetoothProfile.STATE_DISCONNECTED; - }}; + }; + + private static final String PROFILE_API = "BluetoothAdapter_getProfileConnectionState"; - private static final String PROFILE_API = "getProfileConnectionState"; - private final IpcDataCache - mGetProfileConnectionStateCache = - new BluetoothCache(PROFILE_API, mBluetoothProfileQuery); + private final IpcDataCache, Integer> mGetProfileConnectionStateCache = + new BluetoothCache<>(PROFILE_API, mBluetoothProfileQuery); /** * @hide @@ -3085,9 +3095,23 @@ public final class BluetoothAdapter { @SuppressLint("AndroidFrameworkRequiresPermission") public @ConnectionState int getProfileConnectionState(int profile) { if (getState() != STATE_ON) { - return BluetoothProfile.STATE_DISCONNECTED; + return STATE_DISCONNECTED; + } + mServiceLock.readLock().lock(); + try { + if (mService != null) { + return mGetProfileConnectionStateCache.query(new Pair<>(mService, profile)); + } + } catch (RuntimeException e) { + if (!(e.getCause() instanceof TimeoutException) + && !(e.getCause() instanceof RemoteException)) { + throw e; + } + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } finally { + mServiceLock.readLock().unlock(); } - return mGetProfileConnectionStateCache.query(profile); + return STATE_DISCONNECTED; } /** -- cgit v1.2.3