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

Commit 4d870624 authored by Eric Laurent's avatar Eric Laurent Committed by Shunkai Yao
Browse files

AudioService: more logs and test for master mute

Add logging and tests for master mute functions.
Refactor master mute implementation for centralized access
to AudioSystem APIs and logging and store current state in
AudioService.

Bug: 288050380
Test: atest AudioServiceTest
Change-Id: I6755f0411253d65ed83c298835cb27b440759f4e
Merged-In: I6755f0411253d65ed83c298835cb27b440759f4e
parent 30c3601a
Loading
Loading
Loading
Loading
+32 −26
Original line number Diff line number Diff line
@@ -393,6 +393,7 @@ public class AudioService extends IAudioService.Stub
    private static final int MSG_DISPATCH_PREFERRED_MIXER_ATTRIBUTES = 52;
    private static final int MSG_LOWER_VOLUME_TO_RS1 = 53;
    private static final int MSG_CONFIGURATION_CHANGED = 54;
    private static final int MSG_BROADCAST_MASTER_MUTE = 55;
    /** Messages handled by the {@link SoundDoseHelper}. */
    /*package*/ static final int SAFE_MEDIA_VOLUME_MSG_START = 1000;
@@ -975,6 +976,9 @@ public class AudioService extends IAudioService.Stub
    @GuardedBy("mSettingsLock")
    private boolean mRttEnabled = false;
    private AtomicBoolean mMasterMute = new AtomicBoolean(false);
    ///////////////////////////////////////////////////////////////////////////
    // Construction
    ///////////////////////////////////////////////////////////////////////////
@@ -2738,21 +2742,18 @@ public class AudioService extends IAudioService.Stub
        }
        final int currentUser = getCurrentUserId();
        if (mUseFixedVolume) {
            AudioSystem.setMasterVolume(1.0f);
        }
        // Check the current user restriction.
        boolean masterMute =
                mUserManagerInternal.getUserRestriction(currentUser,
                        UserManager.DISALLOW_UNMUTE_DEVICE)
                        || mUserManagerInternal.getUserRestriction(currentUser,
                        UserManager.DISALLOW_ADJUST_VOLUME);
        if (mUseFixedVolume) {
            masterMute = false;
            AudioSystem.setMasterVolume(1.0f);
        }
        if (DEBUG_VOL) {
            Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
        }
        AudioSystem.setMasterMute(masterMute);
        broadcastMasterMuteStatus(masterMute);
        setMasterMuteInternalNoCallerCheck(
                masterMute, /* flags =*/ 0, currentUser, "readUserRestrictions");
        mMicMuteFromRestrictions = mUserManagerInternal.getUserRestriction(
                currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
@@ -4768,16 +4769,10 @@ public class AudioService extends IAudioService.Stub
    // UI update and Broadcast Intent
    private void sendMasterMuteUpdate(boolean muted, int flags) {
        mVolumeController.postMasterMuteChanged(updateFlagsForTvPlatform(flags));
        broadcastMasterMuteStatus(muted);
        sendMsg(mAudioHandler, MSG_BROADCAST_MASTER_MUTE,
                SENDMSG_QUEUE, muted ? 1 : 0, 0, null, 0);
    }
    private void broadcastMasterMuteStatus(boolean muted) {
        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
        sendStickyBroadcastToAll(intent);
    }
    /**
     * Sets the stream state's index, and posts a message to set system volume.
@@ -4944,18 +4939,21 @@ public class AudioService extends IAudioService.Stub
                != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        setMasterMuteInternalNoCallerCheck(mute, flags, userId);
        setMasterMuteInternalNoCallerCheck(mute, flags, userId, "setMasterMute");
    }
    private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
    private void setMasterMuteInternalNoCallerCheck(
            boolean mute, int flags, int userId, String eventSource) {
        if (DEBUG_VOL) {
            Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
            Log.d(TAG, TextUtils.formatSimple("Master mute %s, %d, user=%d from %s",
                    mute, flags, userId, eventSource));
        }
        if (!isPlatformAutomotive() && mUseFixedVolume) {
            // If using fixed volume, we don't mute.
            // TODO: remove the isPlatformAutomotive check here.
            // The isPlatformAutomotive check is added for safety but may not be necessary.
            return;
            mute = false;
        }
        // For automotive,
        // - the car service is always running as system user
@@ -4964,8 +4962,10 @@ public class AudioService extends IAudioService.Stub
        // Therefore, the getCurrentUser() is always different to the foreground user.
        if ((isPlatformAutomotive() && userId == UserHandle.USER_SYSTEM)
                || (getCurrentUserId() == userId)) {
            if (mute != AudioSystem.getMasterMute()) {
                AudioSystem.setMasterMute(mute);
            if (mute != mMasterMute.getAndSet(mute)) {
                sVolumeLogger.enqueue(new VolumeEvent(
                        VolumeEvent.VOL_MASTER_MUTE, mute));
                mAudioSystem.setMasterMute(mute);
                sendMasterMuteUpdate(mute, flags);
            }
        }
@@ -4973,7 +4973,7 @@ public class AudioService extends IAudioService.Stub
    /** get global mute state. */
    public boolean isMasterMute() {
        return AudioSystem.getMasterMute();
        return mMasterMute.get();
    }
    @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
@@ -9278,6 +9278,10 @@ public class AudioService extends IAudioService.Stub
                    mSystemServer.sendMicrophoneMuteChangedIntent();
                    break;
                case MSG_BROADCAST_MASTER_MUTE:
                    mSystemServer.broadcastMasterMuteStatus(msg.arg1 == 1);
                    break;
                case MSG_CHECK_MODE_FOR_UID:
                    synchronized (mDeviceBroker.mSetModeLock) {
                        if (msg.obj == null) {
@@ -9675,7 +9679,8 @@ public class AudioService extends IAudioService.Stub
                        newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
                                || newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_DEVICE);
                if (wasRestricted != isRestricted) {
                    setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
                    setMasterMuteInternalNoCallerCheck(
                            isRestricted, /* flags =*/ 0, userId, "onUserRestrictionsChanged");
                }
            }
        }
@@ -11033,10 +11038,11 @@ public class AudioService extends IAudioService.Stub
            pw.print("  mHdmiCecVolumeControlEnabled="); pw.println(mHdmiCecVolumeControlEnabled);
        }
        pw.print("  mIsCallScreeningModeSupported="); pw.println(mIsCallScreeningModeSupported);
        pw.print("  mic mute FromSwitch=" + mMicMuteFromSwitch
        pw.println("  mic mute FromSwitch=" + mMicMuteFromSwitch
                        + " FromRestrictions=" + mMicMuteFromRestrictions
                        + " FromApi=" + mMicMuteFromApi
                        + " from system=" + mMicMuteFromSystemCached);
        pw.print("  mMasterMute="); pw.println(mMasterMute.get());
        dumpAccessibilityServiceUids(pw);
        dumpAssistantServicesUids(pw);
+19 −0
Original line number Diff line number Diff line
@@ -228,6 +228,7 @@ public class AudioServiceEvents {
        static final int VOL_MUTE_STREAM_INT = 9;
        static final int VOL_SET_LE_AUDIO_VOL = 10;
        static final int VOL_ADJUST_GROUP_VOL = 11;
        static final int VOL_MASTER_MUTE = 12;

        final int mOp;
        final int mStream;
@@ -321,6 +322,17 @@ public class AudioServiceEvents {
            logMetricEvent();
        }

        /** used for VOL_MASTER_MUTE */
        VolumeEvent(int op, boolean state) {
            mOp = op;
            mStream = -1;
            mVal1 = state ? 1 : 0;
            mVal2 = 0;
            mCaller = null;
            mGroupName = null;
            logMetricEvent();
        }


        /**
         * Audio Analytics unique Id.
@@ -429,6 +441,9 @@ public class AudioServiceEvents {
                case VOL_MUTE_STREAM_INT:
                    // No value in logging metrics for this internal event
                    return;
                case VOL_MASTER_MUTE:
                    // No value in logging metrics for this internal event
                    return;
                default:
                    return;
            }
@@ -510,6 +525,10 @@ public class AudioServiceEvents {
                            .append(AudioSystem.streamToString(mStream))
                            .append(mVal1 == 1 ? ", muted)" : ", unmuted)")
                            .toString();
                case VOL_MASTER_MUTE:
                    return new StringBuilder("Master mute:")
                            .append(mVal1 == 1 ? " muted)" : " unmuted)")
                            .toString();
                default: return new StringBuilder("FIXME invalid op:").append(mOp).toString();
            }
        }
+9 −0
Original line number Diff line number Diff line
@@ -684,6 +684,15 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback,
        return AudioSystem.clearPreferredMixerAttributes(attributes, portId, uid);
    }

    /**
     * Sets master mute state in audio flinger
     * @param mute the mute state to set
     * @return operation status
     */
    public int setMasterMute(boolean mute) {
        return AudioSystem.setMasterMute(mute);
    }

    /**
     * Part of AudioService dump
     * @param pw
+14 −0
Original line number Diff line number Diff line
@@ -145,4 +145,18 @@ public class SystemServerAdapter {
            ActivityManager.broadcastStickyIntent(intent, profileId);
        }
    }

    /*package*/ void broadcastMasterMuteStatus(boolean muted) {
        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                | Intent.FLAG_RECEIVER_REPLACE_PENDING
                | Intent.FLAG_RECEIVER_FOREGROUND);
        final long ident = Binder.clearCallingIdentity();
        try {
            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }
}
+32 −8
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ package com.android.server.audio;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.after;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -42,10 +42,10 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

@MediumTest
@RunWith(AndroidJUnit4.class)
@@ -58,7 +58,7 @@ public class AudioServiceTest {
    public final MockitoRule mockito = MockitoJUnit.rule();

    private Context mContext;
    private AudioSystemAdapter mAudioSystem;
    private AudioSystemAdapter mSpyAudioSystem;
    private SettingsAdapter mSettingsAdapter;

    @Spy private NoOpSystemServerAdapter mSpySystemServer;
@@ -78,11 +78,11 @@ public class AudioServiceTest {
            sLooperPrepared = true;
        }
        mContext = InstrumentationRegistry.getTargetContext();
        mAudioSystem = new NoOpAudioSystemAdapter();
        mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
        mSettingsAdapter = new NoOpSettingsAdapter();
        when(mMockAppOpsManager.noteOp(anyInt(), anyInt(), anyString(), anyString(), anyString()))
                .thenReturn(AppOpsManager.MODE_ALLOWED);
        mAudioService = new AudioService(mContext, mAudioSystem, mSpySystemServer,
        mAudioService = new AudioService(mContext, mSpyAudioSystem, mSpySystemServer,
                mSettingsAdapter, mMockAudioPolicy, null, mMockAppOpsManager,
                mMockPermissionEnforcer);
    }
@@ -95,7 +95,7 @@ public class AudioServiceTest {
    public void testMuteMicrophone() throws Exception {
        Log.i(TAG, "running testMuteMicrophone");
        Assert.assertNotNull(mAudioService);
        final NoOpAudioSystemAdapter testAudioSystem = (NoOpAudioSystemAdapter) mAudioSystem;
        final NoOpAudioSystemAdapter testAudioSystem = (NoOpAudioSystemAdapter) mSpyAudioSystem;
        testAudioSystem.configureMuteMicrophoneToFail(false);
        for (boolean muted : new boolean[] { true, false}) {
            testAudioSystem.configureIsMicrophoneMuted(!muted);
@@ -120,7 +120,7 @@ public class AudioServiceTest {
    public void testMuteMicrophoneWhenFail() throws Exception {
        Log.i(TAG, "running testMuteMicrophoneWhenFail");
        Assert.assertNotNull(mAudioService);
        final NoOpAudioSystemAdapter testAudioSystem = (NoOpAudioSystemAdapter) mAudioSystem;
        final NoOpAudioSystemAdapter testAudioSystem = (NoOpAudioSystemAdapter) mSpyAudioSystem;
        testAudioSystem.configureMuteMicrophoneToFail(true);
        for (boolean muted : new boolean[] { true, false}) {
            testAudioSystem.configureIsMicrophoneMuted(!muted);
@@ -175,4 +175,28 @@ public class AudioServiceTest {
        Assert.assertEquals(false, mAudioService.isHotwordStreamSupported(false));
        Assert.assertEquals(false, mAudioService.isHotwordStreamSupported(true));
    }

    /**
     * Test master mute setter and getter
     */
    @Test
    public void testMasterMute() throws Exception {
        Log.i(TAG, "running testMasterMute");
        Assert.assertNotNull(mAudioService);
        for (boolean mute : new boolean[] { true, false}) {
            boolean wasMute = mAudioService.isMasterMute();
            mAudioService.setMasterMute(mute, 0 /* flags */, mContext.getOpPackageName(),
                    UserHandle.getCallingUserId(), null);

            Assert.assertEquals("master mute reporting wrong value",
                    mute, mAudioService.isMasterMute());

            verify(mSpyAudioSystem, times(wasMute == mute ? 0 : 1)).setMasterMute(mute);
            // verify the intent for master mute changed is supposed to be fired
            verify(mSpySystemServer,
                    after(MAX_MESSAGE_HANDLING_DELAY_MS).times(wasMute == mute ? 0 : 1))
                    .broadcastMasterMuteStatus(mute);
            reset(mSpySystemServer);
        }
    }
}
Loading