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

Commit 538eb78c authored by Jean-Michel Trivi's avatar Jean-Michel Trivi Committed by Android (Google) Code Review
Browse files

Merge "Refactor locks in "audio" service for device management"

parents 033ebb43 c4b9c96d
Loading
Loading
Loading
Loading
+170 −105
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@
 */
package com.android.server.audio;

import static com.android.server.audio.AudioService.CONNECTION_STATE_CONNECTED;
import static com.android.server.audio.AudioService.CONNECTION_STATE_DISCONNECTED;

import android.annotation.NonNull;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
@@ -43,7 +46,7 @@ import java.util.ArrayList;
/** @hide */
/*package*/ final class AudioDeviceBroker {

    private static final String TAG = "AudioDeviceBroker";
    private static final String TAG = "AS.AudioDeviceBroker";

    private static final long BROKER_WAKELOCK_TIMEOUT_MS = 5000; //5s

@@ -62,27 +65,27 @@ import java.util.ArrayList;
    private int mForcedUseForCommExt;

    // Manages all connected devices, only ever accessed on the message loop
    //### or make it synchronized
    private final AudioDeviceInventory mDeviceInventory;
    // Manages notifications to BT service
    private final BtHelper mBtHelper;


    //-------------------------------------------------------------------
    // we use a different lock than mDeviceStateLock so as not to create
    // lock contention between enqueueing a message and handling them
    private static final Object sLastDeviceConnectionMsgTimeLock = new Object();
    @GuardedBy("sLastDeviceConnectionMsgTimeLock")
    private static long sLastDeviceConnectMsgTime = 0;

    private final Object mBluetoothA2dpEnabledLock = new Object();
    // General lock to be taken whenever the state of the audio devices is to be checked or changed
    private final Object mDeviceStateLock = new Object();

    // Request to override default use of A2DP for media.
    @GuardedBy("mBluetoothA2dpEnabledLock")
    @GuardedBy("mDeviceStateLock")
    private boolean mBluetoothA2dpEnabled;

    // lock always taken synchronized on mConnectedDevices
    /*package*/  final Object mA2dpAvrcpLock = new Object();
    // lock always taken synchronized on mConnectedDevices
    /*package*/  final Object mHearingAidLock = new Object();

    // lock always taken when accessing AudioService.mSetModeDeathHandlers
    // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
    /*package*/ final Object mSetModeLock = new Object();

    //-------------------------------------------------------------------
@@ -109,13 +112,17 @@ import java.util.ArrayList;
    // All post* methods are asynchronous

    /*package*/ void onSystemReady() {
        synchronized (mDeviceStateLock) {
            mBtHelper.onSystemReady();
        }
    }

    /*package*/ void onAudioServerDied() {
        // Restore forced usage for communications and record
        synchronized (mDeviceStateLock) {
            onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, "onAudioServerDied");
            onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm, "onAudioServerDied");
        }
        // restore devices
        sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE);
    }
@@ -130,8 +137,10 @@ import java.util.ArrayList;
    }

    /*package*/ void disconnectAllBluetoothProfiles() {
        synchronized (mDeviceStateLock) {
            mBtHelper.disconnectAllBluetoothProfiles();
        }
    }

    /**
     * Handle BluetoothHeadset intents where the action is one of
@@ -140,11 +149,13 @@ import java.util.ArrayList;
     * @param intent
     */
    /*package*/ void receiveBtEvent(@NonNull Intent intent) {
        synchronized (mDeviceStateLock) {
            mBtHelper.receiveBtEvent(intent);
        }
    }

    /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) {
        synchronized (mBluetoothA2dpEnabledLock) {
        synchronized (mDeviceStateLock) {
            if (mBluetoothA2dpEnabled == on) {
                return;
            }
@@ -158,6 +169,7 @@ import java.util.ArrayList;
    }

    /*package*/ void setSpeakerphoneOn(boolean on, String eventSource) {
        synchronized (mDeviceStateLock) {
            if (on) {
                if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
                    setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
@@ -170,17 +182,22 @@ import java.util.ArrayList;
            mForcedUseForCommExt = mForcedUseForComm;
            setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
        }
    }

    /*package*/ boolean isSpeakerphoneOn() {
        synchronized (mDeviceStateLock) {
            return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
        }
    }

    /*package*/ void setWiredDeviceConnectionState(int type,
            @AudioService.ConnectionState int state, String address, String name,
            String caller) {
        //TODO move logging here just like in setBluetooth* methods
        synchronized (mDeviceStateLock) {
            mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
        }
    }

    /*package*/ int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
            @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
@@ -192,6 +209,7 @@ import java.util.ArrayList;
                        + " addr=" + device.getAddress()
                        + " prof=" + profile + " supprNoisy=" + suppressNoisyIntent
                        + " vol=" + a2dpVolume)).printLog(TAG));
        synchronized (mDeviceStateLock) {
            if (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE,
                    new BtHelper.BluetoothA2dpDeviceInfo(device))) {
                AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
@@ -199,16 +217,20 @@ import java.util.ArrayList;
                return 0;
            }
            return mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
                device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
                    device, state, profile, suppressNoisyIntent,
                    AudioSystem.DEVICE_NONE, a2dpVolume);
        }
    }

    /*package*/ int handleBluetoothA2dpActiveDeviceChange(
            @NonNull BluetoothDevice device,
            @AudioService.BtProfileConnectionState int state, int profile,
            boolean suppressNoisyIntent, int a2dpVolume) {
        synchronized (mDeviceStateLock) {
            return mDeviceInventory.handleBluetoothA2dpActiveDeviceChange(device, state, profile,
                    suppressNoisyIntent, a2dpVolume);
        }
    }

    /*package*/ int setBluetoothHearingAidDeviceConnectionState(
            @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
@@ -218,21 +240,28 @@ import java.util.ArrayList;
                        + " addr=" + device.getAddress()
                        + " supprNoisy=" + suppressNoisyIntent
                        + " src=" + eventSource)).printLog(TAG));
        synchronized (mDeviceStateLock) {
            return mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
                    device, state, suppressNoisyIntent, musicDevice);
        }
    }

    // never called by system components
    /*package*/ void setBluetoothScoOnByApp(boolean on) {
        synchronized (mDeviceStateLock) {
            mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
        }
    }

    /*package*/ boolean isBluetoothScoOnForApp() {
        synchronized (mDeviceStateLock) {
            return mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO;
        }
    }

    /*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
        //Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
        synchronized (mDeviceStateLock) {
            if (on) {
                // do not accept SCO ON if SCO audio is not connected
                if (!mBtHelper.isBluetoothScoOn()) {
@@ -252,23 +281,28 @@ import java.util.ArrayList;
            // Un-mute ringtone stream volume
            mAudioService.setUpdateRingerModeServiceInt();
        }
    }

    /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
        synchronized (mDeviceStateLock) {
            return mDeviceInventory.startWatchingRoutes(observer);
        }
    }

    /*package*/ AudioRoutesInfo getCurAudioRoutes() {
        synchronized (mDeviceStateLock) {
            return mDeviceInventory.getCurAudioRoutes();
        }
    }

    /*package*/ boolean isAvrcpAbsoluteVolumeSupported() {
        synchronized (mA2dpAvrcpLock) {
        synchronized (mDeviceStateLock) {
            return mBtHelper.isAvrcpAbsoluteVolumeSupported();
        }
    }

    /*package*/ boolean isBluetoothA2dpOn() {
        synchronized (mBluetoothA2dpEnabledLock) {
        synchronized (mDeviceStateLock) {
            return mBluetoothA2dpEnabled;
        }
    }
@@ -355,14 +389,12 @@ import java.util.ArrayList;
        sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
    }

    //###TODO unify with handleSetA2dpSinkConnectionState
    /*package*/ void postA2dpSinkConnection(int state,
            @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
        sendILMsg(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, SENDMSG_QUEUE,
                state, btDeviceInfo, delay);
    }

    //###TODO unify with handleSetA2dpSourceConnectionState
    /*package*/ void postA2dpSourceConnection(int state,
            @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
        sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE,
@@ -395,7 +427,7 @@ import java.util.ArrayList;
                .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
                .append(Binder.getCallingPid()).append(" src:").append(source).toString();

        synchronized (mBluetoothA2dpEnabledLock) {
        synchronized (mDeviceStateLock) {
            mBluetoothA2dpEnabled = on;
            mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE);
            onSetForceUse(
@@ -407,25 +439,38 @@ import java.util.ArrayList;

    /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
                                                       String deviceName) {
        synchronized (mDeviceStateLock) {
            return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName);
        }
    }

    /*package*/ void handleDisconnectA2dp() {
        synchronized (mDeviceStateLock) {
            mDeviceInventory.disconnectA2dp();
        }
    }
    /*package*/ void handleDisconnectA2dpSink() {
        synchronized (mDeviceStateLock) {
            mDeviceInventory.disconnectA2dpSink();
        }
    }

    /*package*/ void handleDisconnectHearingAid() {
        synchronized (mDeviceStateLock) {
            mDeviceInventory.disconnectHearingAid();
        }
    }

    /*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state,
                @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
        final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
        //### DOESN'T HONOR SYNC ON DEVICES -> make a synchronized version?
        // might be ok here because called on BT thread? + sync happening in
        //  checkSendBecomingNoisyIntent
        final int delay = mDeviceInventory.checkSendBecomingNoisyIntent(
        final int intState = (state == BluetoothA2dp.STATE_CONNECTED)
                ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED;
        final int delay;
        synchronized (mDeviceStateLock) {
            delay = mDeviceInventory.checkSendBecomingNoisyIntent(
                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
                    AudioSystem.DEVICE_NONE);
        }
        final String addr = btDeviceInfo == null ? "null" : btDeviceInfo.getBtDevice().getAddress();

        if (AudioService.DEBUG_DEVICES) {
@@ -437,10 +482,6 @@ import java.util.ArrayList;
                state, btDeviceInfo, delay);
    }

    /*package*/ void handleDisconnectHearingAid() {
        mDeviceInventory.disconnectHearingAid();
    }

    /*package*/ void handleSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
            @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
        final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
@@ -468,8 +509,6 @@ import java.util.ArrayList;
        sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo);
    }

    //###
    // must be called synchronized on mConnectedDevices
    /*package*/ boolean hasScheduledA2dpDockTimeout() {
        return mBrokerHandler.hasMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT);
    }
@@ -486,19 +525,19 @@ import java.util.ArrayList;
    }

    /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) {
        synchronized (mA2dpAvrcpLock) {
        synchronized (mDeviceStateLock) {
            mBtHelper.setAvrcpAbsoluteVolumeSupported(supported);
        }
    }

    /*package*/ boolean getBluetoothA2dpEnabled() {
        synchronized (mBluetoothA2dpEnabledLock) {
        synchronized (mDeviceStateLock) {
            return mBluetoothA2dpEnabled;
        }
    }

    /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) {
        synchronized (mA2dpAvrcpLock) {
        synchronized (mDeviceStateLock) {
            return mBtHelper.getA2dpCodec(device);
        }
    }
@@ -579,71 +618,97 @@ import java.util.ArrayList;
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_RESTORE_DEVICES:
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.onRestoreDevices();
                    synchronized (mBluetoothA2dpEnabledLock) {
                        mBtHelper.onAudioServerDiedRestoreA2dp();
                    }
                    break;
                case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.onSetWiredDeviceConnectionState(
                                (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);
                    }
                    break;
                case MSG_I_BROADCAST_BT_CONNECTION_STATE:
                    synchronized (mDeviceStateLock) {
                        mBtHelper.onBroadcastScoConnectionState(msg.arg1);
                    }
                    break;
                case MSG_IIL_SET_FORCE_USE: // intented fall-through
                case MSG_IIL_SET_FORCE_USE: // intended fall-through
                case MSG_IIL_SET_FORCE_BT_A2DP_USE:
                    onSetForceUse(msg.arg1, msg.arg2, (String) msg.obj);
                    break;
                case MSG_REPORT_NEW_ROUTES:
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.onReportNewRoutes();
                    }
                    break;
                case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE:
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.onSetA2dpSinkConnectionState(
                                (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
                    }
                    break;
                case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.onSetA2dpSourceConnectionState(
                                (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
                    }
                    break;
                case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.onSetHearingAidConnectionState(
                                (BluetoothDevice) msg.obj, msg.arg1);
                    }
                    break;
                case MSG_BT_HEADSET_CNCT_FAILED:
                    synchronized (mDeviceStateLock) {
                        mBtHelper.resetBluetoothSco();
                    }
                    break;
                case MSG_IL_BTA2DP_DOCK_TIMEOUT:
                    // msg.obj  == address of BTA2DP device
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1);
                    }
                    break;
                case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
                    final int a2dpCodec;
                    final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
                    synchronized (mA2dpAvrcpLock) {
                    synchronized (mDeviceStateLock) {
                        a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
                    }
                        mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
                                new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec));
                    }
                    break;
                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
                    onSendBecomingNoisyIntent();
                    break;
                case MSG_II_SET_HEARING_AID_VOLUME:
                    synchronized (mDeviceStateLock) {
                        mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
                    }
                    break;
                case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME:
                    synchronized (mDeviceStateLock) {
                        mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
                    }
                    break;
                case MSG_I_DISCONNECT_BT_SCO:
                    synchronized (mDeviceStateLock) {
                        mBtHelper.disconnectBluetoothSco(msg.arg1);
                    }
                    break;
                case MSG_TOGGLE_HDMI:
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.onToggleHdmi();
                    }
                    break;
                case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
                                (BtHelper.BluetoothA2dpDeviceInfo) msg.obj);
                    }
                    break;
                default:
                    Log.wtf(TAG, "Invalid message " + msg.what);
+32 −37
Original line number Diff line number Diff line
@@ -162,10 +162,7 @@ public final class AudioDeviceInventory {
                "A2DP sink connected: device addr=" + address + " state=" + state
                        + " vol=" + a2dpVolume));

        final int a2dpCodec;
        synchronized (mDeviceBroker.mA2dpAvrcpLock) {
            a2dpCodec = btInfo.getCodec();
        }
        final int a2dpCodec = btInfo.getCodec();

        synchronized (mConnectedDevices) {
            final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
@@ -508,7 +505,6 @@ public final class AudioDeviceInventory {

    /*package*/ void disconnectA2dp() {
        synchronized (mConnectedDevices) {
            synchronized (mDeviceBroker.mA2dpAvrcpLock) {
            final ArraySet<String> toRemove = new ArraySet<>();
            // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
            mConnectedDevices.values().forEach(deviceInfo -> {
@@ -519,14 +515,13 @@ public final class AudioDeviceInventory {
            if (toRemove.size() > 0) {
                final int delay = checkSendBecomingNoisyIntentInt(
                        AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                            0, AudioSystem.DEVICE_NONE);
                        AudioService.CONNECTION_STATE_DISCONNECTED, AudioSystem.DEVICE_NONE);
                toRemove.stream().forEach(deviceAddress ->
                        makeA2dpDeviceUnavailableLater(deviceAddress, delay)
                );
            }
        }
    }
    }

    /*package*/ void disconnectA2dpSink() {
        synchronized (mConnectedDevices) {
@@ -543,7 +538,6 @@ public final class AudioDeviceInventory {

    /*package*/ void disconnectHearingAid() {
        synchronized (mConnectedDevices) {
            synchronized (mDeviceBroker.mHearingAidLock) {
            final ArraySet<String> toRemove = new ArraySet<>();
            // Disconnect ALL DEVICE_OUT_HEARING_AID devices
            mConnectedDevices.values().forEach(deviceInfo -> {
@@ -561,12 +555,12 @@ public final class AudioDeviceInventory {
            }
        }
    }
    }

    // must be called before removing the device from mConnectedDevices
    // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
    // from AudioSystem
    /*package*/ int checkSendBecomingNoisyIntent(int device, int state, int musicDevice) {
    /*package*/ int checkSendBecomingNoisyIntent(int device,
            @AudioService.ConnectionState int state, int musicDevice) {
        synchronized (mConnectedDevices) {
            return checkSendBecomingNoisyIntentInt(device, state, musicDevice);
        }
@@ -840,8 +834,9 @@ public final class AudioDeviceInventory {
    // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
    // from AudioSystem
    @GuardedBy("mConnectedDevices")
    private int checkSendBecomingNoisyIntentInt(int device, int state, int musicDevice) {
        if (state != 0) {
    private int checkSendBecomingNoisyIntentInt(int device,
            @AudioService.ConnectionState int state, int musicDevice) {
        if (state != AudioService.CONNECTION_STATE_DISCONNECTED) {
            return 0;
        }
        if ((device & mBecomingNoisyIntentDevices) == 0) {
+0 −2
Original line number Diff line number Diff line
@@ -786,7 +786,6 @@ public class AudioService extends IAudioService.Stub
                mPrescaleAbsoluteVolume[i] = preScale[i];
            }
        }

    }

    public void systemReady() {
@@ -3821,7 +3820,6 @@ public class AudioService extends IAudioService.Stub

    private static void sendMsg(Handler handler, int msg,
            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {

        if (existingMsgPolicy == SENDMSG_REPLACE) {
            handler.removeMessages(msg);
        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
+245 −274

File changed.

Preview size limit exceeded, changes collapsed.