summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Eric Laurent <elaurent@google.com> 2022-09-20 00:43:05 +0000
committer Eric Laurent <elaurent@google.com> 2022-10-05 19:07:31 +0000
commit8a1cbede1dba2cd359324aaef245b4dbd49b9e90 (patch)
tree5893c5a7af082cb0db57fe5628562c2a3508a19a
parent3e5c74adf4c36aee6f635dfae4a686eb8a15ee2c (diff)
AudioService: fix unsafe volume playback time accumulation
Use the AlarmManager and intents as periodic timer instead of the message handler when accumulating the playback time with unsafe volume levels. Using the handler was not counting time spend in suspend which happens when using offload playback. Bug: 244322644 Test: repo steps in bug Change-Id: Ife6fda6120b9a2d6c30cc87a76be1521416c0628 (cherry picked from commit 92cb946d7fbb01d1683aa6c3dff2e29f41b573a9)
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java111
1 files changed, 71 insertions, 40 deletions
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0b6b89074cfc..02bfdfc7b076 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -41,10 +41,12 @@ import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IUidObserver;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
import android.bluetooth.BluetoothAdapter;
@@ -1185,6 +1187,8 @@ public class AudioService extends IAudioService.Stub
mSafeMediaVolumeIndex = mContext.getResources().getInteger(
com.android.internal.R.integer.config_safe_media_volume_index) * 10;
+ mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
mUseFixedVolume = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useFixedVolume);
@@ -1202,7 +1206,7 @@ public class AudioService extends IAudioService.Stub
mPlaybackMonitor =
new PlaybackActivityMonitor(context, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM],
device -> onMuteAwaitConnectionTimeout(device));
- mPlaybackMonitor.registerPlaybackCallback(mVoicePlaybackActivityMonitor, true);
+ mPlaybackMonitor.registerPlaybackCallback(mPlaybackActivityMonitor, true);
mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
@@ -1308,6 +1312,7 @@ public class AudioService extends IAudioService.Stub
intentFilter.addAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
intentFilter.addAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
+ intentFilter.addAction(ACTION_CHECK_MUSIC_ACTIVE);
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null,
Context.RECEIVER_EXPORTED);
@@ -1927,13 +1932,7 @@ public class AudioService extends IAudioService.Stub
if (state == AudioService.CONNECTION_STATE_CONNECTED) {
// DEVICE_OUT_HDMI is now connected
if (mSafeMediaVolumeDevices.contains(AudioSystem.DEVICE_OUT_HDMI)) {
- sendMsg(mAudioHandler,
- MSG_CHECK_MUSIC_ACTIVE,
- SENDMSG_REPLACE,
- 0,
- 0,
- caller,
- MUSIC_ACTIVE_POLL_PERIOD_MS);
+ scheduleMusicActiveCheck();
}
if (isPlatformTelevision()) {
@@ -3822,8 +3821,9 @@ public class AudioService extends IAudioService.Stub
}
private AtomicBoolean mVoicePlaybackActive = new AtomicBoolean(false);
+ private AtomicBoolean mMediaPlaybackActive = new AtomicBoolean(false);
- private final IPlaybackConfigDispatcher mVoicePlaybackActivityMonitor =
+ private final IPlaybackConfigDispatcher mPlaybackActivityMonitor =
new IPlaybackConfigDispatcher.Stub() {
@Override
public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
@@ -3836,19 +3836,26 @@ public class AudioService extends IAudioService.Stub
private void onPlaybackConfigChange(List<AudioPlaybackConfiguration> configs) {
boolean voiceActive = false;
+ boolean mediaActive = false;
for (AudioPlaybackConfiguration config : configs) {
final int usage = config.getAudioAttributes().getUsage();
- if ((usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
- || usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING)
- && config.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ if (!config.isActive()) {
+ continue;
+ }
+ if (usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
+ || usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING) {
voiceActive = true;
- break;
+ }
+ if (usage == AudioAttributes.USAGE_MEDIA || usage == AudioAttributes.USAGE_GAME) {
+ mediaActive = true;
}
}
if (mVoicePlaybackActive.getAndSet(voiceActive) != voiceActive) {
updateHearingAidVolumeOnVoiceActivityUpdate();
}
-
+ if (mMediaPlaybackActive.getAndSet(mediaActive) != mediaActive && mediaActive) {
+ scheduleMusicActiveCheck();
+ }
// Update playback active state for all apps in audio mode stack.
// When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE
// and request an audio mode update immediately. Upon any other change, queue the message
@@ -6032,30 +6039,52 @@ public class AudioService extends IAudioService.Stub
return mContentResolver;
}
+ private void scheduleMusicActiveCheck() {
+ synchronized (mSafeMediaVolumeStateLock) {
+ cancelMusicActiveCheck();
+ mMusicActiveIntent = PendingIntent.getBroadcast(mContext,
+ REQUEST_CODE_CHECK_MUSIC_ACTIVE,
+ new Intent(ACTION_CHECK_MUSIC_ACTIVE),
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime()
+ + MUSIC_ACTIVE_POLL_PERIOD_MS, mMusicActiveIntent);
+ }
+ }
+
+ private void cancelMusicActiveCheck() {
+ synchronized (mSafeMediaVolumeStateLock) {
+ if (mMusicActiveIntent != null) {
+ mAlarmManager.cancel(mMusicActiveIntent);
+ mMusicActiveIntent = null;
+ }
+ }
+ }
private void onCheckMusicActive(String caller) {
synchronized (mSafeMediaVolumeStateLock) {
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
-
- if (mSafeMediaVolumeDevices.contains(device)) {
- sendMsg(mAudioHandler,
- MSG_CHECK_MUSIC_ACTIVE,
- SENDMSG_REPLACE,
- 0,
- 0,
- caller,
- MUSIC_ACTIVE_POLL_PERIOD_MS);
+ if (mSafeMediaVolumeDevices.contains(device)
+ && mAudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
+ scheduleMusicActiveCheck();
int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
- if (mAudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)
- && (index > safeMediaVolumeIndex(device))) {
+ if (index > safeMediaVolumeIndex(device)) {
// Approximate cumulative active music time
- mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
+ long curTimeMs = SystemClock.elapsedRealtime();
+ if (mLastMusicActiveTimeMs != 0) {
+ mMusicActiveMs += (int) (curTimeMs - mLastMusicActiveTimeMs);
+ }
+ mLastMusicActiveTimeMs = curTimeMs;
+ Log.i(TAG, "onCheckMusicActive() mMusicActiveMs: " + mMusicActiveMs);
if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
setSafeMediaVolumeEnabled(true, caller);
mMusicActiveMs = 0;
}
saveMusicActiveMs();
}
+ } else {
+ cancelMusicActiveCheck();
+ mLastMusicActiveTimeMs = 0;
}
}
}
@@ -6124,6 +6153,7 @@ public class AudioService extends IAudioService.Stub
} else {
// We have existing playback time recorded, already confirmed.
mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
+ mLastMusicActiveTimeMs = 0;
}
}
} else {
@@ -8633,13 +8663,7 @@ public class AudioService extends IAudioService.Stub
@VisibleForTesting
public void checkMusicActive(int deviceType, String caller) {
if (mSafeMediaVolumeDevices.contains(deviceType)) {
- sendMsg(mAudioHandler,
- MSG_CHECK_MUSIC_ACTIVE,
- SENDMSG_REPLACE,
- 0,
- 0,
- caller,
- MUSIC_ACTIVE_POLL_PERIOD_MS);
+ scheduleMusicActiveCheck();
}
}
@@ -8764,6 +8788,8 @@ public class AudioService extends IAudioService.Stub
suspendedPackages[i], suspendedUids[i]);
}
}
+ } else if (action.equals(ACTION_CHECK_MUSIC_ACTIVE)) {
+ onCheckMusicActive(ACTION_CHECK_MUSIC_ACTIVE);
}
}
} // end class AudioServiceBroadcastReceiver
@@ -9709,12 +9735,20 @@ public class AudioService extends IAudioService.Stub
// When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
// automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
private int mMusicActiveMs;
+ private long mLastMusicActiveTimeMs = 0;
+ private PendingIntent mMusicActiveIntent = null;
+ private AlarmManager mAlarmManager;
+
private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
// check playback or record activity every 6 seconds for UIDs owning mode IN_COMMUNICATION
private static final int CHECK_MODE_FOR_UID_PERIOD_MS = 6000;
+ private static final String ACTION_CHECK_MUSIC_ACTIVE =
+ AudioService.class.getSimpleName() + ".CHECK_MUSIC_ACTIVE";
+ private static final int REQUEST_CODE_CHECK_MUSIC_ACTIVE = 1;
+
private int safeMediaVolumeIndex(int device) {
if (!mSafeMediaVolumeDevices.contains(device)) {
return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
@@ -9736,14 +9770,9 @@ public class AudioService extends IAudioService.Stub
} else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
mMusicActiveMs = 1; // nonzero = confirmed
+ mLastMusicActiveTimeMs = 0;
saveMusicActiveMs();
- sendMsg(mAudioHandler,
- MSG_CHECK_MUSIC_ACTIVE,
- SENDMSG_REPLACE,
- 0,
- 0,
- caller,
- MUSIC_ACTIVE_POLL_PERIOD_MS);
+ scheduleMusicActiveCheck();
}
}
}
@@ -9785,7 +9814,9 @@ public class AudioService extends IAudioService.Stub
public void disableSafeMediaVolume(String callingPackage) {
enforceVolumeController("disable the safe media volume");
synchronized (mSafeMediaVolumeStateLock) {
+ final long identity = Binder.clearCallingIdentity();
setSafeMediaVolumeEnabled(false, callingPackage);
+ Binder.restoreCallingIdentity(identity);
if (mPendingVolumeCommand != null) {
onSetStreamVolume(mPendingVolumeCommand.mStreamType,
mPendingVolumeCommand.mIndex,