From e5a351cb9213b59026efd602011a4d9e99c85649 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 27 Sep 2017 20:11:51 -0700 Subject: Fix Cell broadcast sound in total silence PlayerBase: Update player volume when the audio attributes are updated in case we need to unmute PlaybackActivityMonitor: Unmute alarm stream if needed when an alarm with flag FLAG_BYPASS_INTERRUPTION_POLICY starts from an app with privileged permission MODIFY_PHONE_STATE. Bug: 63617557 Test: check sound with cell broadcast in total silence Change-Id: Ifacb1d96a2d8d44047d9f9642d1e672fcf756cda --- media/java/android/media/PlayerBase.java | 21 +++++----- .../com/android/server/audio/AudioService.java | 5 ++- .../server/audio/PlaybackActivityMonitor.java | 45 +++++++++++++++++++++- 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index 4808d7a5aa6a..09449a183d96 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -127,8 +127,9 @@ public abstract class PlayerBase { Log.e(TAG, "Error talking to audio service, STARTED state will not be tracked", e); } synchronized (mLock) { + boolean attributesChanged = (mAttributes != attr); mAttributes = attr; - updateAppOpsPlayAudio_sync(); + updateAppOpsPlayAudio_sync(attributesChanged); } } @@ -200,16 +201,13 @@ public abstract class PlayerBase { } void baseSetVolume(float leftVolume, float rightVolume) { - final boolean hasAppOpsPlayAudio; + final boolean isRestricted; synchronized (mLock) { mLeftVolume = leftVolume; mRightVolume = rightVolume; - hasAppOpsPlayAudio = mHasAppOpsPlayAudio; - if (isRestricted_sync()) { - return; - } + isRestricted = isRestricted_sync(); } - playerSetVolume(!hasAppOpsPlayAudio/*muting*/, + playerSetVolume(isRestricted/*muting*/, leftVolume * mPanMultiplierL, rightVolume * mPanMultiplierR); } @@ -250,7 +248,7 @@ public abstract class PlayerBase { private void updateAppOpsPlayAudio() { synchronized (mLock) { - updateAppOpsPlayAudio_sync(); + updateAppOpsPlayAudio_sync(false); } } @@ -258,7 +256,7 @@ public abstract class PlayerBase { * To be called whenever a condition that might affect audibility of this player is updated. * Must be called synchronized on mLock. */ - void updateAppOpsPlayAudio_sync() { + void updateAppOpsPlayAudio_sync(boolean attributesChanged) { boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio; try { int mode = AppOpsManager.MODE_IGNORED; @@ -275,9 +273,10 @@ public abstract class PlayerBase { // AppsOps alters a player's volume; when the restriction changes, reflect it on the actual // volume used by the player try { - if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) { + if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio || + attributesChanged) { getService().playerHasOpPlayAudio(mPlayerIId, mHasAppOpsPlayAudio); - if (mHasAppOpsPlayAudio) { + if (!isRestricted_sync()) { if (DEBUG_APP_OPS) { Log.v(TAG, "updateAppOpsPlayAudio: unmuting player, vol=" + mLeftVolume + "/" + mRightVolume); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 3c1f2d42707a..8739496a7749 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -751,6 +751,9 @@ public class AudioService extends IAudioService.Stub // relies on audio policy having correct ranges for volume indexes. mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex(); + mPlaybackMonitor = + new PlaybackActivityMonitor(context, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]); + mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor); mRecordMonitor = new RecordingActivityMonitor(mContext); @@ -6972,7 +6975,7 @@ public class AudioService extends IAudioService.Stub //====================== // Audio playback notification //====================== - private final PlaybackActivityMonitor mPlaybackMonitor = new PlaybackActivityMonitor(); + private final PlaybackActivityMonitor mPlaybackMonitor; public void registerPlaybackCallback(IPlaybackConfigDispatcher pcdb) { final boolean isPrivileged = diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index d1a37af5e7a8..512f72a60dea 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -17,6 +17,8 @@ package com.android.server.audio; import android.annotation.NonNull; +import android.content.Context; +import android.content.pm.PackageManager; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioPlaybackConfiguration; @@ -90,7 +92,14 @@ public final class PlaybackActivityMonitor private final HashMap mPlayers = new HashMap(); - PlaybackActivityMonitor() { + private final Context mContext; + private int mSavedAlarmVolume = -1; + private final int mMaxAlarmVolume; + private int mPrivilegedAlarmActiveCount = 0; + + PlaybackActivityMonitor(Context context, int maxAlarmVolume) { + mContext = context; + mMaxAlarmVolume = maxAlarmVolume; PlayMonitorClient.sListenerDeathMonitor = this; AudioPlaybackConfiguration.sPlayerDeathMonitor = this; } @@ -175,6 +184,38 @@ public final class PlaybackActivityMonitor } } + private void checkVolumeForPrivilegedAlarm(AudioPlaybackConfiguration apc, int event) { + if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED || + apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { + if ((apc.getAudioAttributes().getAllFlags() & + AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0 && + apc.getAudioAttributes().getUsage() == AudioAttributes.USAGE_ALARM && + mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, + apc.getClientPid(), apc.getClientUid()) == + PackageManager.PERMISSION_GRANTED) { + if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED && + apc.getPlayerState() != AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { + if (mPrivilegedAlarmActiveCount++ == 0) { + mSavedAlarmVolume = AudioSystem.getStreamVolumeIndex( + AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER); + AudioSystem.setStreamVolumeIndex(AudioSystem.STREAM_ALARM, + mMaxAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER); + } + } else if (event != AudioPlaybackConfiguration.PLAYER_STATE_STARTED && + apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { + if (--mPrivilegedAlarmActiveCount == 0) { + if (AudioSystem.getStreamVolumeIndex( + AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER) == + mMaxAlarmVolume) { + AudioSystem.setStreamVolumeIndex(AudioSystem.STREAM_ALARM, + mSavedAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER); + } + } + } + } + } + } + public void playerEvent(int piid, int event, int binderUid) { if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d)", piid, event)); } final boolean change; @@ -200,6 +241,7 @@ public final class PlaybackActivityMonitor } if (checkConfigurationCaller(piid, apc, binderUid)) { //TODO add generation counter to only update to the latest state + checkVolumeForPrivilegedAlarm(apc, event); change = apc.handleStateEvent(event); } else { Log.e(TAG, "Error handling event " + event); @@ -228,6 +270,7 @@ public final class PlaybackActivityMonitor "releasing player piid:" + piid)); mPlayers.remove(new Integer(piid)); mDuckingManager.removeReleased(apc); + checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED); apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED); } } -- cgit v1.2.3-59-g8ed1b