Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1145987a authored by Jakub Rotkiewicz's avatar Jakub Rotkiewicz
Browse files

A2dpStateMachine: ignore connect events in connecting state

After bonding the enabled profiles are connected automatically:

BluetoothAdapterService: connectEnabledProfiles: Connecting A2dp

and this may happen multiple times. Additionally during testing
A2dpService::connect() may be invoked causing 2 redundant connect calls
that happen in Connecting state of the A2DP state machine. The events are
then deferred, and on any failure and the state change to Disconnected
they are being invoked again in Disconnected state...

While trying to handle collisions in AVDTP this is problematic, hence
this change neglects connect events when in Connecting state,
but only if there are no disconnect events already deferred. This helped as now
we allow the peer device to proceed with the connection as initiator and
we do not collide again.

Bug: 329809288
Flag: com.android.bluetooth.flags.a2dp_sm_ignore_connect_events_in_connecting_state
Test: atest A2dpStateMachine
Change-Id: I956c3a2a0bd8382654fdbdd0ffc593083b6d100f
parent cfae36f8
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -328,7 +328,14 @@ final class A2dpStateMachine extends StateMachine {
                            + messageWhatToString(message.what));

            switch (message.what) {
                case MESSAGE_CONNECT -> deferMessage(message);
                case MESSAGE_CONNECT -> {
                    if (Flags.a2dpSmIgnoreConnectEventsInConnectingState()
                            && !hasDeferredMessages(MESSAGE_DISCONNECT)) {
                        Log.w(TAG, "Connecting: CONNECT ignored: " + mDevice);
                    } else {
                        deferMessage(message);
                    }
                }
                case MESSAGE_CONNECT_TIMEOUT -> {
                    Log.w(TAG, "Connecting connection timeout: " + mDevice);
                    mA2dpNativeInterface.disconnectA2dp(mDevice);
+23 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;

import static com.android.bluetooth.a2dp.A2dpStateMachine.MESSAGE_CONNECT;
import static com.android.bluetooth.a2dp.A2dpStateMachine.MESSAGE_DISCONNECT;
import static com.android.bluetooth.a2dp.A2dpStateMachine.MESSAGE_STACK_EVENT;

import static com.google.common.truth.Truth.assertThat;
@@ -47,11 +48,14 @@ import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.os.test.TestLooper;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;

import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.TestUtils;
import com.android.bluetooth.flags.Flags;

import org.hamcrest.Matcher;
import org.hamcrest.core.AllOf;
@@ -72,6 +76,8 @@ import java.util.Arrays;
public class A2dpStateMachineTest {
    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Mock private A2dpService mService;
    @Mock private A2dpNativeInterface mNativeInterface;

@@ -327,6 +333,23 @@ public class A2dpStateMachineTest {
        mStateMachine.dump(new StringBuilder());
    }

    @Test
    @EnableFlags(Flags.FLAG_A2DP_SM_IGNORE_CONNECT_EVENTS_IN_CONNECTING_STATE)
    public void connectEventNeglectedWhileInConnectingState() {
        sendAndDispatchMessage(MESSAGE_CONNECT, mDevice);
        verifyConnectionStateIntent(STATE_CONNECTING, STATE_DISCONNECTED);
        assertThat(mStateMachine.getCurrentState()).isInstanceOf(A2dpStateMachine.Connecting.class);

        // Dispatch CONNECT event twice more
        sendAndDispatchMessage(MESSAGE_CONNECT, mDevice);
        sendAndDispatchMessage(MESSAGE_CONNECT, mDevice);
        sendAndDispatchMessage(MESSAGE_DISCONNECT, mDevice);
        verifyConnectionStateIntent(STATE_DISCONNECTED, STATE_CONNECTING);
        assertThat(mStateMachine.getCurrentState())
                .isInstanceOf(A2dpStateMachine.Disconnected.class);
        assertThat(mLooper.dispatchAll()).isEqualTo(0);
    }

    private void sendAndDispatchMessage(int what, Object obj) {
        mStateMachine.sendMessage(what, obj);
        mLooper.dispatchAll();