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

Commit d9422cca authored by xiaotonj's avatar xiaotonj
Browse files

Protect audio communication device set/clear operations with a lock.

Currently, when telecom audio stack handle series messages relate to
communication device set/clear operations, these operations will be
completed in random order which will cause unexpected device set as the
communication device. Protect these operations with a lock to avoid race
conditions.

Bug: b/303001133
Test: atest CallAudioRouteStateMachineTest
Change-Id: Ib9fcbc712aaa3583ceea17288fa85ac33c0e7d3c
parent cf22ed22
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -41,3 +41,10 @@ flag {
  description: "Refactor call audio set/clear communication device and include unsupported routes."
  bug: "308968392"
}

flag {
  name: "communication_device_protected_by_lock"
  namespace: "telecom"
  description: "Protect set/clear communication device operation with lock to avoid race condition."
  bug: "303001133"
}
+15 −0
Original line number Diff line number Diff line
@@ -24,10 +24,12 @@ import android.telecom.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
import com.android.server.telecom.flags.Flags;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Semaphore;

/**
 * Helper class used to keep track of the requested communication device within Telecom for audio
@@ -50,6 +52,7 @@ public class CallAudioCommunicationDeviceTracker {
    private int mAudioDeviceType = sAUDIO_DEVICE_TYPE_INVALID;
    // Keep track of the locally requested BT audio device if set
    private String mBtAudioDevice = null;
    private final Semaphore mLock =  new Semaphore(1);

    public CallAudioCommunicationDeviceTracker(Context context) {
        mAudioManager = context.getSystemService(AudioManager.class);
@@ -94,6 +97,9 @@ public class CallAudioCommunicationDeviceTracker {
     */
    public boolean setCommunicationDevice(int audioDeviceType,
            BluetoothDevice btDevice) {
        if (Flags.communicationDeviceProtectedByLock()) {
            mLock.tryAcquire();
        }
        // There is only one audio device type associated with each type of BT device.
        boolean isBtDevice = sBT_AUDIO_DEVICE_TYPES.contains(audioDeviceType);
        Log.i(this, "setCommunicationDevice: type = %s, isBtDevice = %s, btDevice = %s",
@@ -155,6 +161,9 @@ public class CallAudioCommunicationDeviceTracker {
                }
            }
        }
        if (Flags.communicationDeviceProtectedByLock()) {
            mLock.release();
        }
        return result;
    }

@@ -164,6 +173,9 @@ public class CallAudioCommunicationDeviceTracker {
     * @param audioDeviceTypes The supported audio device types for the device.
     */
    public void clearCommunicationDevice(int audioDeviceType) {
        if (Flags.communicationDeviceProtectedByLock()) {
            mLock.tryAcquire();
        }
        // There is only one audio device type associated with each type of BT device.
        boolean isBtDevice = sBT_AUDIO_DEVICE_TYPES.contains(audioDeviceType);
        Log.i(this, "clearCommunicationDevice: type = %s, isBtDevice = %s",
@@ -195,6 +207,9 @@ public class CallAudioCommunicationDeviceTracker {
            mBluetoothRouteManager.onAudioLost(mBtAudioDevice);
            mBtAudioDevice = null;
        }
        if (Flags.communicationDeviceProtectedByLock()) {
            mLock.release();
        }
    }

    private boolean isUsbHeadsetType(int audioDeviceType, int sourceType) {