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

Commit bc75e6fa authored by Jack He's avatar Jack He Committed by Gerrit Code Review
Browse files

Merge changes I666db6a8,I6480b9f5 into main

* changes:
  LeAudioService: Replace `synchronized(mGroupLock)` with ReentrantLock
  Flags: leaudio_api_synchronized_block_fix
parents e06192d2 923fbc39
Loading
Loading
Loading
Loading
+140 −37
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
@@ -143,7 +144,7 @@ public class LeAudioService extends ProfileService {
    private volatile BluetoothDevice mActiveBroadcastAudioDevice;
    private BluetoothDevice mExposedActiveDevice;
    private LeAudioCodecConfig mLeAudioCodecConfig;
    private final Object mGroupLock = new Object();
    private final ReentrantLock mGroupLock = new ReentrantLock();
    private FeatureFlags mFeatureFlags;
    ServiceFactory mServiceFactory = new ServiceFactory();

@@ -339,9 +340,12 @@ public class LeAudioService extends ProfileService {

        mBroadcastDescriptors.clear();

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            mDeviceDescriptors.clear();
            mGroupDescriptors.clear();
        } finally {
            mGroupLock.unlock();
        }

        // Setup broadcast callbacks
@@ -430,7 +434,8 @@ public class LeAudioService extends ProfileService {

        // Don't wait for async call with INACTIVE group status, clean active
        // device for active group.
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (Map.Entry<Integer, LeAudioGroupDescriptor> entry : mGroupDescriptors.entrySet()) {
                LeAudioGroupDescriptor descriptor = entry.getValue();
                Integer group_id = entry.getKey();
@@ -454,6 +459,8 @@ public class LeAudioService extends ProfileService {

            mDeviceDescriptors.clear();
            mGroupDescriptors.clear();
        } finally {
            mGroupLock.unlock();
        }

        // Cleanup native interfaces
@@ -607,7 +614,8 @@ public class LeAudioService extends ProfileService {
            return false;
        }

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            boolean isInbandRingtoneEnabled = false;
            int groupId = getGroupId(device);
            if (groupId != LE_AUDIO_GROUP_ID_INVALID) {
@@ -624,6 +632,8 @@ public class LeAudioService extends ProfileService {
                return false;
            }
            sm.sendMessage(LeAudioStateMachine.CONNECT);
        } finally {
            mGroupLock.unlock();
        }

        return true;
@@ -640,7 +650,8 @@ public class LeAudioService extends ProfileService {
            Log.d(TAG, "disconnect(): " + device);
        }

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
            if (descriptor == null) {
                Log.e(TAG, "disconnect: No valid descriptor for device: " + device);
@@ -655,13 +666,16 @@ public class LeAudioService extends ProfileService {
            }

            sm.sendMessage(LeAudioStateMachine.DISCONNECT);
        } finally {
            mGroupLock.unlock();
        }

        return true;
    }

    public List<BluetoothDevice> getConnectedDevices() {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            List<BluetoothDevice> devices = new ArrayList<>();
            for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
                LeAudioStateMachine sm = descriptor.mStateMachine;
@@ -670,6 +684,8 @@ public class LeAudioService extends ProfileService {
                }
            }
            return devices;
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -690,7 +706,8 @@ public class LeAudioService extends ProfileService {
        if (bondedDevices == null) {
            return devices;
        }
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (BluetoothDevice device : bondedDevices) {
                final ParcelUuid[] featureUuids = device.getUuids();
                if (!Utils.arrayContains(featureUuids, BluetoothUuid.LE_AUDIO)) {
@@ -716,6 +733,8 @@ public class LeAudioService extends ProfileService {
                }
            }
            return devices;
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -727,13 +746,16 @@ public class LeAudioService extends ProfileService {
    @VisibleForTesting
    List<BluetoothDevice> getDevices() {
        List<BluetoothDevice> devices = new ArrayList<>();
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
                if (descriptor.mStateMachine != null) {
                    devices.add(descriptor.mStateMachine.getDevice());
                }
            }
            return devices;
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -747,7 +769,8 @@ public class LeAudioService extends ProfileService {
     * {@link BluetoothProfile#STATE_DISCONNECTING} if this profile is being disconnected
     */
    public int getConnectionState(BluetoothDevice device) {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
            if (descriptor == null) {
                return BluetoothProfile.STATE_DISCONNECTED;
@@ -758,6 +781,8 @@ public class LeAudioService extends ProfileService {
                return BluetoothProfile.STATE_DISCONNECTED;
            }
            return sm.getConnectionState();
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -795,8 +820,11 @@ public class LeAudioService extends ProfileService {
     * @return true given group exists, otherwise false
     */
    public boolean isValidDeviceGroup(int groupId) {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            return groupId != LE_AUDIO_GROUP_ID_INVALID && mGroupDescriptors.containsKey(groupId);
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -812,13 +840,16 @@ public class LeAudioService extends ProfileService {
            return result;
        }

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
                    : mDeviceDescriptors.entrySet()) {
                if (entry.getValue().mGroupId == groupId) {
                    result.add(entry.getKey());
                }
            }
        } finally {
            mGroupLock.unlock();
        }
        return result;
    }
@@ -836,13 +867,16 @@ public class LeAudioService extends ProfileService {
            return result;
        }

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
                    : mDeviceDescriptors.entrySet()) {
                if (entry.getValue().mGroupId == groupId) {
                    result.add(entry.getKey());
                }
            }
        } finally {
            mGroupLock.unlock();
        }
        return result;
    }
@@ -851,13 +885,16 @@ public class LeAudioService extends ProfileService {
     * Get the active device group id
     */
    public Integer getActiveGroupId() {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (Map.Entry<Integer, LeAudioGroupDescriptor> entry : mGroupDescriptors.entrySet()) {
                LeAudioGroupDescriptor descriptor = entry.getValue();
                if (descriptor.mIsActive) {
                    return entry.getKey();
                }
            }
        } finally {
            mGroupLock.unlock();
        }
        return LE_AUDIO_GROUP_ID_INVALID;
    }
@@ -1177,13 +1214,16 @@ public class LeAudioService extends ProfileService {
    }

    private boolean areAllGroupsInNotActiveState() {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (Map.Entry<Integer, LeAudioGroupDescriptor> entry : mGroupDescriptors.entrySet()) {
                LeAudioGroupDescriptor descriptor = entry.getValue();
                if (descriptor.mIsActive) {
                    return false;
                }
            }
        } finally {
            mGroupLock.unlock();
        }
        return true;
    }
@@ -1192,7 +1232,8 @@ public class LeAudioService extends ProfileService {
        if (groupId == LE_AUDIO_GROUP_ID_INVALID) {
            return null;
        }
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioGroupDescriptor groupDescriptor = getGroupDescriptor(groupId);
            if (groupDescriptor == null) {
                Log.e(TAG, "Group " + groupId + " does not exist");
@@ -1217,6 +1258,8 @@ public class LeAudioService extends ProfileService {
                groupDescriptor.mCurrentLeadDevice = sm.getDevice();
                return groupDescriptor.mCurrentLeadDevice;
            }
        } finally {
            mGroupLock.unlock();
        }
        return null;
    }
@@ -1447,7 +1490,8 @@ public class LeAudioService extends ProfileService {
    }

    boolean allLeAudioDevicesConnected() {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> deviceEntry :
                    mDeviceDescriptors.entrySet()) {
                LeAudioDeviceDescriptor deviceDescriptor = deviceEntry.getValue();
@@ -1462,6 +1506,8 @@ public class LeAudioService extends ProfileService {
                    return false;
                }
            }
        } finally {
            mGroupLock.unlock();
        }
        return true;
    }
@@ -1721,7 +1767,8 @@ public class LeAudioService extends ProfileService {
    }

    private void clearInactiveDueToContextTypeFlags() {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (Map.Entry<Integer, LeAudioGroupDescriptor> groupEntry :
                    mGroupDescriptors.entrySet()) {
                LeAudioGroupDescriptor groupDescriptor = groupEntry.getValue();
@@ -1732,6 +1779,8 @@ public class LeAudioService extends ProfileService {
                    groupDescriptor.mInactivatedDueToContextType = false;
                }
            }
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -1948,7 +1997,8 @@ public class LeAudioService extends ProfileService {
                Log.d(TAG, "connect(): " + storedDevice);
            }

            synchronized (mGroupLock) {
            mGroupLock.lock();
            try {
                LeAudioStateMachine sm = getOrCreateStateMachine(storedDevice);
                if (sm == null) {
                    Log.e(TAG, "Ignored connect request for " + storedDevice
@@ -1956,6 +2006,8 @@ public class LeAudioService extends ProfileService {
                    continue;
                }
                sm.sendMessage(LeAudioStateMachine.CONNECT);
            } finally {
                mGroupLock.unlock();
            }
        }
    }
@@ -1975,7 +2027,8 @@ public class LeAudioService extends ProfileService {
    }

    private void clearLostDevicesWhileStreaming(LeAudioGroupDescriptor descriptor) {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            if (DBG) {
                Log.d(TAG, "Clearing lost dev: " + descriptor.mLostLeadDeviceWhileStreaming);
            }
@@ -1998,6 +2051,8 @@ public class LeAudioService extends ProfileService {
                sm.sendMessage(LeAudioStateMachine.STACK_EVENT, stackEvent);
            }
            descriptor.mLostLeadDeviceWhileStreaming = null;
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -2074,7 +2129,8 @@ public class LeAudioService extends ProfileService {
    }

    private void handleGroupTransitToActive(int groupId) {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
            if (descriptor == null || descriptor.mIsActive) {
                Log.e(TAG, "handleGroupTransitToActive: no descriptors for group: " + groupId
@@ -2089,11 +2145,14 @@ public class LeAudioService extends ProfileService {
                notifyGroupStatusChanged(groupId, LeAudioStackEvent.GROUP_STATUS_ACTIVE);
                updateInbandRingtoneForTheGroup(groupId);
            }
        } finally {
            mGroupLock.unlock();
        }
    }

    private void handleGroupTransitToInactive(int groupId) {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
            if (descriptor == null || !descriptor.mIsActive) {
                Log.e(TAG, "handleGroupTransitToInactive: no descriptors for group: " + groupId
@@ -2127,6 +2186,8 @@ public class LeAudioService extends ProfileService {
            clearLostDevicesWhileStreaming(descriptor);
            notifyGroupStatusChanged(groupId, LeAudioStackEvent.GROUP_STATUS_INACTIVE);
            updateInbandRingtoneForTheGroup(groupId);
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -2235,7 +2296,8 @@ public class LeAudioService extends ProfileService {
            return;
        }

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioGroupDescriptor groupDescriptor = getGroupDescriptor(groupId);
            if (groupDescriptor == null) {
                Log.e(TAG, "group descriptor for " + groupId + " does not exist");
@@ -2293,6 +2355,8 @@ public class LeAudioService extends ProfileService {
                    }
                }
            }
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -2415,7 +2479,8 @@ public class LeAudioService extends ProfileService {

        if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) {
            // Some events require device state machine
            synchronized (mGroupLock) {
            mGroupLock.lock();
            try {
                LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
                if (deviceDescriptor == null) {
                    Log.e(TAG, "messageFromNative: No valid descriptor for device: " + device);
@@ -2492,6 +2557,8 @@ public class LeAudioService extends ProfileService {

                sm.sendMessage(LeAudioStateMachine.STACK_EVENT, stackEvent);
                return;
            } finally {
                mGroupLock.unlock();
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_GROUP_NODE_STATUS_CHANGED) {
            int groupId = stackEvent.valueInt1;
@@ -2561,7 +2628,8 @@ public class LeAudioService extends ProfileService {
            int src_audio_location = stackEvent.valueInt4;
            int available_contexts = stackEvent.valueInt5;

            synchronized (mGroupLock) {
            mGroupLock.lock();
            try {
                LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
                if (descriptor != null) {
                    if (descriptor.mIsActive) {
@@ -2588,6 +2656,8 @@ public class LeAudioService extends ProfileService {
                } else {
                    Log.e(TAG, "messageFromNative: no descriptors for group: " + groupId);
                }
            } finally {
                mGroupLock.unlock();
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE) {
            Objects.requireNonNull(stackEvent.device,
@@ -2885,7 +2955,8 @@ public class LeAudioService extends ProfileService {
            return;
        }

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
            if (descriptor == null) {
                Log.e(TAG, "bondStateChanged: No valid descriptor for device: " + device);
@@ -2912,11 +2983,14 @@ public class LeAudioService extends ProfileService {
            }
            removeStateMachine(device);
            removeAuthorizationInfoForRelatedProfiles(device);
        } finally {
            mGroupLock.unlock();
        }
    }

    private void removeStateMachine(BluetoothDevice device) {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
            if (descriptor == null) {
                Log.e(TAG, "removeStateMachine: No valid descriptor for device: " + device);
@@ -2938,6 +3012,8 @@ public class LeAudioService extends ProfileService {
            if (!isScannerNeeded()) {
                stopAudioServersBackgroundScan();
            }
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -2987,7 +3063,8 @@ public class LeAudioService extends ProfileService {
     * Process a change for disconnection of a device.
     */
    public synchronized void deviceDisconnected(BluetoothDevice device, boolean hasFallbackDevice) {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
            if (deviceDescriptor == null) {
                Log.e(TAG, "deviceDisconnected: No valid descriptor for device: " + device);
@@ -3049,6 +3126,8 @@ public class LeAudioService extends ProfileService {
                        hasFallbackDevice,
                        false);
            }
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -3298,7 +3377,8 @@ public class LeAudioService extends ProfileService {
            return LE_AUDIO_GROUP_ID_INVALID;
        }

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
            if (descriptor == null) {
                Log.e(TAG, "getGroupId: No valid descriptor for device: " + device);
@@ -3306,6 +3386,8 @@ public class LeAudioService extends ProfileService {
            }

            return descriptor.mGroupId;
        } finally {
            mGroupLock.unlock();
        }
    }

@@ -3411,37 +3493,50 @@ public class LeAudioService extends ProfileService {

        mBluetoothEnabled = true;

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            if (mDeviceDescriptors.isEmpty()) {
                return;
            }
        } finally {
            mGroupLock.unlock();
        }

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (BluetoothDevice device : mDeviceDescriptors.keySet()) {
                if (getConnectionPolicy(device) != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
                    setAuthorizationForRelatedProfiles(device, true);
                }
            }
        } finally {
            mGroupLock.unlock();
        }

        startAudioServersBackgroundScan(/* retry = */ false);
    }

    private LeAudioGroupDescriptor getGroupDescriptor(int groupId) {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            return mGroupDescriptors.get(groupId);
        } finally {
            mGroupLock.unlock();
        }
    }

    private LeAudioDeviceDescriptor getDeviceDescriptor(BluetoothDevice device) {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            return mDeviceDescriptors.get(device);
        } finally {
            mGroupLock.unlock();
        }
    }

    private void handleGroupNodeAdded(BluetoothDevice device, int groupId) {
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            if (DBG) {
                Log.d(TAG, "Device " + device + " added to group " + groupId);
            }
@@ -3475,6 +3570,8 @@ public class LeAudioService extends ProfileService {
            deviceDescriptor.mGroupId = groupId;

            notifyGroupNodeAdded(device, groupId);
        } finally {
            mGroupLock.unlock();
        }

        if (mBluetoothEnabled) {
@@ -3507,7 +3604,8 @@ public class LeAudioService extends ProfileService {
            Log.d(TAG, "Removing device " + device + " grom group " + groupId);
        }

        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            LeAudioGroupDescriptor groupDescriptor = getGroupDescriptor(groupId);
            if (groupDescriptor == null) {
                Log.e(TAG, "handleGroupNodeRemoved: No valid descriptor for group: " + groupId);
@@ -3551,6 +3649,8 @@ public class LeAudioService extends ProfileService {
                }
            }
            notifyGroupNodeRemoved(device, groupId);
        } finally {
            mGroupLock.unlock();
        }

        setAuthorizationForRelatedProfiles(device, false);
@@ -4617,7 +4717,8 @@ public class LeAudioService extends ProfileService {
                                + mLeAudioInbandRingtoneSupportedByPlatform);

        int numberOfUngroupedDevs = 0;
        synchronized (mGroupLock) {
        mGroupLock.lock();
        try {
            for (Map.Entry<Integer, LeAudioGroupDescriptor> groupEntry
                                                : mGroupDescriptors.entrySet()) {
                LeAudioGroupDescriptor groupDescriptor = groupEntry.getValue();
@@ -4661,6 +4762,8 @@ public class LeAudioService extends ProfileService {
                    ProfileService.println(sb, "    mDirection: " + deviceDescriptor.mDirection);
                }
            }
        } finally {
            mGroupLock.unlock();
        }

        if (numberOfUngroupedDevs > 0) {
+10 −0
Original line number Diff line number Diff line
@@ -159,3 +159,13 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "leaudio_api_synchronized_block_fix"
    namespace: "bluetooth"
    description: "Fix possible deadlocks when synchronizing LeAudioService states"
    bug: "326295400"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}