Get bluetooth state on the BluetoothRouteManager looper
When calling getCurrentState() on a state machine from outside its
looper, an ArrayOutOfBoundsException may occur if the state machine is
mid-transition. This change moves the call to getCurrentState into a
Runnable that's run on the looper.
Change-Id: I079552541367733bad5aad1ca6753529f0043143
Fixes: 37224925
Test: manual
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index 494089b..e3d99d9 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -29,6 +29,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.IState;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.telecom.BluetoothHeadsetProxy;
@@ -43,6 +44,8 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
public class BluetoothRouteManager extends StateMachine {
private static final String LOG_TAG = BluetoothRouteManager.class.getSimpleName();
@@ -581,8 +584,27 @@
return mDeviceManager.getNumConnectedDevices() > 0;
}
+ /**
+ * This method needs be synchronized with the local looper because getCurrentState() depends
+ * on the internal state of the state machine being consistent. Therefore, there may be a
+ * delay when calling this method.
+ * @return
+ */
public boolean isBluetoothAudioConnectedOrPending() {
- return getCurrentState() != mAudioOffState;
+ IState[] state = new IState[] {null};
+ CountDownLatch latch = new CountDownLatch(1);
+ Runnable r = () -> {
+ state[0] = getCurrentState();
+ latch.countDown();
+ };
+ sendMessage(RUN_RUNNABLE, r);
+ try {
+ latch.await(1000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Log.w(LOG_TAG, "isBluetoothAudioConnectedOrPending -- interrupted getting state");
+ return false;
+ }
+ return (state[0] != null) && (state[0] != mAudioOffState);
}
/**