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
This commit is contained in:
Dongwon Kang
2015-06-16 15:28:17 -07:00
parent 2d4dc8db64
commit a38e1f4ed9
2 changed files with 28 additions and 8 deletions

View File

@@ -40,7 +40,7 @@ import android.view.KeyEvent;
*/
interface IAudioService {
void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage, String caller);
void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage);

View File

@@ -242,19 +242,17 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
// Adjust the volume with a handler not to be blocked by other system service.
if (useSuggested) {
if (AudioSystem.isStreamActive(stream, 0)) {
mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
flags, packageName, uid);
postAdjustSuggestedStreamVolume(stream, direction, flags, packageName, uid);
} else {
flags |= previousFlagPlaySound;
mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName,
uid);
postAdjustSuggestedStreamVolume(AudioManager.USE_DEFAULT_STREAM_TYPE, direction,
flags, packageName, uid);
}
} else {
mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
packageName, uid);
postAdjustStreamVolume(stream, direction, flags, packageName, uid);
}
} else {
if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
@@ -461,6 +459,28 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
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() {
int fields = mMetadata == null ? 0 : mMetadata.size();
MediaDescription description = mMetadata == null ? null : mMetadata