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

Commit d45a4a2e authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Have AudioService listen to DISALLOW_UNMUTE_MICROPHONE and

... DISALLOW_ADJUST_VOLUME, instead of UserManager pushing
new settings to AudioService.

Also:
- Allow PO to set these two restrictions.

- Now AS.setMasterMuteInternal() respects mUseFixedVolume to make
it consistent with readPersistedSettings().

- When a user switches and restores the mute state in
AS.readPersistedSettings(), also check the current user restrictions
in addition to system settings. Because of the delay in AudioService
before persisting the mute settings in setMasterMuteInternal() and
setMicrophoneMute(), there's was an edge case
DISALLOW_UNMUTE_MICROPHONE and DISALLOW_ADJUST_VOLUME would be ignored
when the user switches right after they are set.

Bug 24981972

Change-Id: I4d9b709a0a0e6812319204568c6e44d6664bdeb4
parent b59db97f
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -19,6 +19,17 @@ package android.os;
 * @hide Only for use within the system server.
 */
public abstract class UserManagerInternal {
    public interface UserRestrictionsListener {
        /**
         * Called when a user restriction changes.
         *
         * @param userId target user id
         * @param newRestrictions new user restrictions
         * @param prevRestrictions user restrictions that were previously set
         */
        void onUserRestrictionsChanged(int userId, Bundle newRestrictions, Bundle prevRestrictions);
    }

    /**
     * Lock that must be held when calling certain methods in this class.
     *
@@ -60,4 +71,13 @@ public abstract class UserManagerInternal {
     */
    public abstract void setBaseUserRestrictionsByDpmsForMigration(int userId,
            Bundle baseRestrictions);

    /** Return a user restriction. */
    public abstract boolean getUserRestriction(int userId, String key);

    /** Adds a listener to user restriction changes. */
    public abstract void addUserRestrictionsListener(UserRestrictionsListener listener);

    /** Remove a {@link UserRestrictionsListener}. */
    public abstract void removeUserRestrictionsListener(UserRestrictionsListener listener);
}
+78 −4
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ import android.media.audiopolicy.AudioPolicyConfig;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -88,6 +89,8 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
import android.os.Vibrator;
import android.provider.Settings;
import android.provider.Settings.System;
@@ -397,6 +400,12 @@ public class AudioService extends IAudioService.Stub {
    // Broadcast receiver for device connections intent broadcasts
    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();

    /** Interface for UserManagerService. */
    private final UserManagerInternal mUserManagerInternal;

    private final UserRestrictionsListener mUserRestrictionsListener =
            new AudioServiceUserRestrictionsListener();

    // Devices currently connected
    // Use makeDeviceListKey() to make a unique key for this list.
    private class DeviceListSpec {
@@ -598,6 +607,8 @@ public class AudioService extends IAudioService.Stub {

        mPlatformType = AudioSystem.getPlatformType(context);

        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);

        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");

@@ -694,6 +705,8 @@ public class AudioService extends IAudioService.Stub {
        context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);

        LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());

        mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
    }

    public void systemReady() {
@@ -1039,17 +1052,32 @@ public class AudioService extends IAudioService.Stub {
                System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
                UserHandle.USER_CURRENT);

        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
                0, UserHandle.USER_CURRENT) == 1;
        final int currentUser = getCurrentUserId();

        // In addition to checking the system setting, also check the current user restriction.
        // Because of the delay before persisting VOLUME_MASTER_MUTE, there's a window where
        // DISALLOW_ADJUST_VOLUME will be ignored when it's set right before switching users.
        boolean masterMute = (System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
                0, UserHandle.USER_CURRENT) == 1)
                || 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);

        boolean microphoneMute =
                System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
                (System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1)
                || mUserManagerInternal.getUserRestriction(
                        currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
        if (DEBUG_VOL) {
            Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
        }
        AudioSystem.muteMicrophone(microphoneMute);

        // Each stream will read its own persisted settings
@@ -1767,6 +1795,16 @@ public class AudioService extends IAudioService.Stub {
                != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        setMasterMuteInternalNoCallerCheck(mute, flags, userId);
    }

    private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
        if (DEBUG_VOL) {
            Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
        }
        if (mUseFixedVolume) {
            return; // If using fixed volume, we don't mute.
        }
        if (getCurrentUserId() == userId) {
            if (mute != AudioSystem.getMasterMute()) {
                setSystemAudioMute(mute);
@@ -1841,7 +1879,8 @@ public class AudioService extends IAudioService.Stub {
        return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
    }

    /** @see AudioManager#setMicrophoneMute(boolean, int) */
    /** @see AudioManager#setMicrophoneMute(boolean) */
    @Override
    public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
        // If we are being called by the system check for user we are going to change
        // so we handle user restrictions correctly.
@@ -1863,7 +1902,13 @@ public class AudioService extends IAudioService.Stub {
                != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        setMicrophoneMuteNoCallerCheck(on, userId);
    }

    private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
        if (DEBUG_VOL) {
            Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
        }
        // If mute is for current user actually mute, else just persist the setting
        // which will be loaded on user switch.
        if (getCurrentUserId() == userId) {
@@ -5116,6 +5161,35 @@ public class AudioService extends IAudioService.Stub {
        }
    } // end class AudioServiceBroadcastReceiver

    private class AudioServiceUserRestrictionsListener implements UserRestrictionsListener {

        @Override
        public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
                Bundle prevRestrictions) {
            // Update mic mute state.
            {
                final boolean wasRestricted =
                        prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
                final boolean isRestricted =
                        newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
                if (wasRestricted != isRestricted) {
                    setMicrophoneMuteNoCallerCheck(isRestricted, userId);
                }
            }

            // Update speaker mute state.
            {
                final boolean wasRestricted =
                        prevRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME);
                final boolean isRestricted =
                        newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME);
                if (wasRestricted != isRestricted) {
                    setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
                }
            }
        }
    } // end class AudioServiceUserRestrictionsListener

    private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
        PackageManager pm = mContext.getPackageManager();
        // Find the home activity of the user. It should not be killed to avoid expensive restart,
+57 −2
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.system.ErrnoException;
@@ -232,6 +233,10 @@ public class UserManagerService extends IUserManager.Stub {

    private final LocalService mLocalService;

    @GuardedBy("mUserRestrictionsListeners")
    private final ArrayList<UserRestrictionsListener> mUserRestrictionsListeners =
            new ArrayList<>();

    private static UserManagerService sInstance;

    public static UserManagerService getInstance() {
@@ -781,7 +786,14 @@ public class UserManagerService extends IUserManager.Stub {

    @GuardedBy("mRestrictionsLock")
    private void applyUserRestrictionsLR(int userId, Bundle newRestrictions) {
        final Bundle prevRestrictions = mAppliedUserRestrictions.get(userId);
        if (newRestrictions == null) {
            newRestrictions = Bundle.EMPTY;
        }

        Bundle prevRestrictions = mAppliedUserRestrictions.get(userId);
        if (prevRestrictions == null) {
            prevRestrictions = Bundle.EMPTY;
        }

        if (DBG) {
            Log.d(LOG_TAG, "applyUserRestrictionsRL userId=" + userId
@@ -797,12 +809,36 @@ public class UserManagerService extends IUserManager.Stub {
            Binder.restoreCallingIdentity(token);
        }

        UserRestrictionsUtils.applyUserRestrictions(
        UserRestrictionsUtils.applyUserRestrictionsLR(
                mContext, userId, newRestrictions, prevRestrictions);

        notifyUserRestrictionsListeners(userId, newRestrictions, prevRestrictions);

        mAppliedUserRestrictions.put(userId, new Bundle(newRestrictions));
    }

    private void notifyUserRestrictionsListeners(final int userId,
            Bundle newRestrictions, Bundle prevRestrictions) {

        final Bundle newRestrictionsFinal = new Bundle(newRestrictions);
        final Bundle prevRestrictionsFinal = new Bundle(prevRestrictions);

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                final UserRestrictionsListener[] listeners;
                synchronized (mUserRestrictionsListeners) {
                    listeners = new UserRestrictionsListener[mUserRestrictionsListeners.size()];
                    mUserRestrictionsListeners.toArray(listeners);
                }
                for (int i = 0; i < listeners.length; i++) {
                    listeners[i].onUserRestrictionsChanged(userId,
                            newRestrictionsFinal, prevRestrictionsFinal);
                }
            }
        });
    }

    @GuardedBy("mRestrictionsLock")
    private void updateEffectiveUserRestrictionsLR(int userId) {
        updateUserRestrictionsInternalLR(null, userId);
@@ -2388,6 +2424,25 @@ public class UserManagerService extends IUserManager.Stub {
                }
            }
        }

        @Override
        public boolean getUserRestriction(int userId, String key) {
            return getUserRestrictions(userId).getBoolean(key);
        }

        @Override
        public void addUserRestrictionsListener(UserRestrictionsListener listener) {
            synchronized (mUserRestrictionsListeners) {
                mUserRestrictionsListeners.add(listener);
            }
        }

        @Override
        public void removeUserRestrictionsListener(UserRestrictionsListener listener) {
            synchronized (mUserRestrictionsListeners) {
                mUserRestrictionsListeners.remove(listener);
            }
        }
    }

    private class Shell extends ShellCommand {
+20 −25
Original line number Diff line number Diff line
@@ -18,19 +18,14 @@ package com.android.server.pm;

import com.google.android.collect.Sets;

import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.media.IAudioService;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
@@ -39,6 +34,11 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;

/**
 * Utility methods for uesr restrictions.
 *
 * <p>See {@link UserManagerService} for the method suffixes.
 */
public class UserRestrictionsUtils {
    private static final String TAG = "UserRestrictionsUtils";

@@ -129,26 +129,31 @@ public class UserRestrictionsUtils {
    /**
     * Takes a new use restriction set and the previous set, and apply the restrictions that have
     * changed.
     *
     * <p>Note this method is called by {@link UserManagerService} while holding
     * {@code mRestrictionLock}. Be aware when calling into other services, which could cause
     * a deadlock.
     */
    public static void applyUserRestrictions(Context context, int userId,
            @Nullable Bundle newRestrictions, @Nullable Bundle prevRestrictions) {
        if (newRestrictions == null) {
            newRestrictions = Bundle.EMPTY;
        }
        if (prevRestrictions == null) {
            prevRestrictions = Bundle.EMPTY;
        }
    public static void applyUserRestrictionsLR(Context context, int userId,
            Bundle newRestrictions, Bundle prevRestrictions) {
        for (String key : USER_RESTRICTIONS) {
            final boolean newValue = newRestrictions.getBoolean(key);
            final boolean prevValue = prevRestrictions.getBoolean(key);

            if (newValue != prevValue) {
                applyUserRestriction(context, userId, key, newValue);
                applyUserRestrictionLR(context, userId, key, newValue);
            }
        }
    }

    private static void applyUserRestriction(Context context, int userId, String key,
    /**
     * Apply each user restriction.
     *
     * <p>Note this method is called by {@link UserManagerService} while holding
     * {@code mRestrictionLock}. Be aware when calling into other services, which could cause
     * a deadlock.
     */
    private static void applyUserRestrictionLR(Context context, int userId, String key,
            boolean newValue) {
        // When certain restrictions are cleared, we don't update the system settings,
        // because these settings are changeable on the Settings UI and we don't know the original
@@ -161,14 +166,6 @@ public class UserRestrictionsUtils {
        final long id = Binder.clearCallingIdentity();
        try {
            switch (key) {
                case UserManager.DISALLOW_UNMUTE_MICROPHONE:
                    IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE))
                            .setMicrophoneMute(newValue, context.getPackageName(), userId);
                    break;
                case UserManager.DISALLOW_ADJUST_VOLUME:
                    IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE))
                            .setMasterMute(newValue, 0, context.getPackageName(), userId);
                    break;
                case UserManager.DISALLOW_CONFIG_WIFI:
                    if (newValue) {
                        android.provider.Settings.Secure.putIntForUser(cr,
@@ -231,8 +228,6 @@ public class UserRestrictionsUtils {
                    }
                    break;
            }
        } catch (RemoteException re) {
            Slog.e(TAG, "Failed to talk to AudioService.", re);
        } finally {
            Binder.restoreCallingIdentity(id);
        }
+0 −4
Original line number Diff line number Diff line
@@ -212,8 +212,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
        DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
        DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
        DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_UNMUTE_MICROPHONE);
        DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_ADJUST_VOLUME);
        DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_SMS);
        DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_FUN);
        DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_SAFE_BOOT);
@@ -4648,7 +4646,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            mIPackageManager.updatePermissionFlagsForAllApps(
                    PackageManager.FLAG_PERMISSION_POLICY_FIXED,
                    0  /* flagValues */, userHandle.getIdentifier());
            // TODO This will not revert audio mute restrictions if they were set.  b/24981972
            synchronized (mUserManagerInternal.getUserRestrictionsLock()) {
                mUserManagerInternal.updateEffectiveUserRestrictionsLR(userHandle.getIdentifier());
            }
@@ -5599,7 +5596,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner) {
        Preconditions.checkNotNull(who, "ComponentName is null");
        final int userHandle = mInjector.userHandleGetCallingUserId();
        final UserHandle user = new UserHandle(userHandle);
        synchronized (mUserManagerInternal.getUserRestrictionsLock()) {
            synchronized (this) {
                ActiveAdmin activeAdmin =