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

Commit 0cd2c709 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "AudioService: fix unsafe volume playback time accumulation"

parents 8f760708 92cb946d
Loading
Loading
Loading
Loading
+71 −40
Original line number Diff line number Diff line
@@ -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;
@@ -1190,6 +1192,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);
@@ -1207,7 +1211,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);
@@ -1313,6 +1317,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);
@@ -1932,13 +1937,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()) {
@@ -3827,8 +3826,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,
@@ -3841,19 +3841,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
@@ -6036,30 +6043,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;
                }
            }
        }
@@ -6128,6 +6157,7 @@ public class AudioService extends IAudioService.Stub
                        } else {
                            // We have existing playback time recorded, already confirmed.
                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
                            mLastMusicActiveTimeMs = 0;
                        }
                    }
                } else {
@@ -8637,13 +8667,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();
        }
    }
@@ -8768,6 +8792,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
@@ -9713,12 +9739,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];
@@ -9740,14 +9774,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();
                }
            }
        }
@@ -9789,7 +9818,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,