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

Commit a38e1f4e authored by Dongwon Kang's avatar Dongwon Kang
Browse files

Make MediaSessionService not blocked by AudioService.

Backgroud: As noted in b/20823981, MediaSessionService calls some
audio service methods while holding a lock and the audio service
methods also talk to other system services. And, deadlock happens when
the other system service fires another request to MediaSessionService
while holding its lock.

Example1) --- resolved by the change in MediaSessionRecord.java
T1: MediaSessionService.dispatchAdjustVolumeLocked()
     -> MediaSessionRecord.adjustVolume()
       -> +++AudioServiceInternal.adjustSuggestedStreamVolumeForUid()+++
         -> AudioService.adjustSuggestedStreamVolume()
           -> telecom.TelecomManager.isInCall() --- blocked by lock in TelecomManager.
T2: telecom.ConnectionServiceWrapper.handleCreateConnectionComplete()
     -> MediaSession.setActive()
       -> MediaSessionRecord$SessionStub.setActive()
         -> MediaSessionService.updateSession() --- blocked by lock in MediaSessionService.

Example2) --- resolved by the change in IAudioService.aidl
T1: MediaSessionService.dispatchAdjustVolumeLocked()
     -> IAudioService.adjustSuggestedStreamVolume()
       -> AudioService.adjustSuggestedStreamVolume()
         -> telecom.TelecomManager.isInCall() --- blocked by lock in TelecomManager.
T2: telecom.ConnectionServiceWrapper.handleCreateConnectionComplete()
     -> MediaSession.setActive()
       -> MediaSessionRecord$SessionStub.setActive()
         -> MediaSessionService.updateSession() --- blocked by lock in MediaSessionService.

Here, this change prevents the deadlock by making related audio IPC oneway
and calling the internal audio method without holding the lock.

Bug: 20823981
Change-Id: I4c4b2fc796f23d83be67f7edaacd7496c145d985
parent 2d4dc8db
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -40,7 +40,7 @@ import android.view.KeyEvent;
 */
 */
interface IAudioService {
interface IAudioService {


    void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
    oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
            String callingPackage, String caller);
            String callingPackage, String caller);


    void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage);
    void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage);
+27 −7
Original line number Original line Diff line number Diff line
@@ -242,19 +242,17 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
        }
        }
        if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
        if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
            int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
            int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
            // Adjust the volume with a handler not to be blocked by other system service.
            if (useSuggested) {
            if (useSuggested) {
                if (AudioSystem.isStreamActive(stream, 0)) {
                if (AudioSystem.isStreamActive(stream, 0)) {
                    mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
                    postAdjustSuggestedStreamVolume(stream, direction, flags, packageName, uid);
                            flags, packageName, uid);
                } else {
                } else {
                    flags |= previousFlagPlaySound;
                    flags |= previousFlagPlaySound;
                    mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
                    postAdjustSuggestedStreamVolume(AudioManager.USE_DEFAULT_STREAM_TYPE, direction,
                            AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName,
                            flags, packageName, uid);
                            uid);
                }
                }
            } else {
            } else {
                mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
                postAdjustStreamVolume(stream, direction, flags, packageName, uid);
                        packageName, uid);
            }
            }
        } else {
        } else {
            if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
            if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
@@ -461,6 +459,28 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
        return mPackageName + "/" + mTag;
        return mPackageName + "/" + mTag;
    }
    }


    private void postAdjustSuggestedStreamVolume(final int streamType, final int direction,
            final int flags, final String callingPackage, final int uid) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(streamType, direction,
                        flags, callingPackage, uid);
            }
        });
    }

    private void postAdjustStreamVolume(final int streamType, final int direction, final int flags,
            final String callingPackage, final int uid) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mAudioManagerInternal.adjustStreamVolumeForUid(streamType, direction, flags,
                        callingPackage, uid);
            }
        });
    }

    private String getShortMetadataString() {
    private String getShortMetadataString() {
        int fields = mMetadata == null ? 0 : mMetadata.size();
        int fields = mMetadata == null ? 0 : mMetadata.size();
        MediaDescription description = mMetadata == null ? null : mMetadata
        MediaDescription description = mMetadata == null ? null : mMetadata