Loading media/java/android/media/AudioManager.java +52 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.media; import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT; import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.media.audio.Flags.autoPublicVolumeApiHardening; import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API; import android.Manifest; Loading Loading @@ -49,6 +50,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.media.AudioAttributes.AttributeSystemUsage; import android.media.CallbackUtil.ListenerInfo; import android.media.audiopolicy.AudioPolicy; Loading Loading @@ -901,6 +903,7 @@ public class AudioManager { @UnsupportedAppUsage public AudioManager(Context context) { setContext(context); initPlatform(); } private Context getContext() { Loading @@ -914,6 +917,9 @@ public class AudioManager { } private void setContext(Context context) { if (context == null) { return; } mOriginalContextDeviceId = context.getDeviceId(); mApplicationContext = context.getApplicationContext(); if (mApplicationContext != null) { Loading Loading @@ -1063,9 +1069,18 @@ public class AudioManager { * @see #isVolumeFixed() */ public void adjustVolume(int direction, @PublicVolumeFlags int flags) { if (applyAutoHardening()) { final IAudioService service = getService(); try { service.adjustVolume(direction, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags); } } /** * Adjusts the volume of the most relevant stream, or the given fallback Loading Loading @@ -1093,9 +1108,18 @@ public class AudioManager { */ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, @PublicVolumeFlags int flags) { if (applyAutoHardening()) { final IAudioService service = getService(); try { service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags); } } /** @hide */ @UnsupportedAppUsage Loading Loading @@ -9969,6 +9993,30 @@ public class AudioManager { } } //==================================================================== // Flag related utilities private boolean mIsAutomotive = false; private void initPlatform() { try { final Context context = getContext(); if (context != null) { mIsAutomotive = context.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); } } catch (Exception e) { Log.e(TAG, "Error querying system feature for AUTOMOTIVE", e); } } private boolean applyAutoHardening() { if (mIsAutomotive && autoPublicVolumeApiHardening()) { return true; } return false; } //--------------------------------------------------------- // Inner classes //-------------------- Loading media/java/android/media/IAudioService.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -500,6 +500,10 @@ interface IAudioService { in String packageName, int uid, int pid, in UserHandle userHandle, int targetSdkVersion); oneway void adjustVolume(int direction, int flags); oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags); boolean isMusicActive(in boolean remotely); int getDeviceMaskForStream(in int streamType); Loading services/core/java/com/android/server/audio/AudioService.java +73 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.server.audio; import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED; import static android.app.BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT; import static android.media.audio.Flags.autoPublicVolumeApiHardening; import static android.media.audio.Flags.focusFreezeTestApi; import static android.media.AudioDeviceInfo.TYPE_BLE_HEADSET; import static android.media.AudioDeviceInfo.TYPE_BLE_SPEAKER; import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP; Loading Loading @@ -157,6 +159,7 @@ import android.media.permission.SafeCloseable; import android.media.projection.IMediaProjection; import android.media.projection.IMediaProjectionCallback; import android.media.projection.IMediaProjectionManager; import android.media.session.MediaSessionManager; import android.net.Uri; import android.os.Binder; import android.os.Build; Loading Loading @@ -314,6 +317,9 @@ public class AudioService extends IAudioService.Stub private final ContentResolver mContentResolver; private final AppOpsManager mAppOps; /** do not use directly, use getMediaSessionManager() which handles lazy initialization */ @Nullable private volatile MediaSessionManager mMediaSessionManager; // the platform type affects volume and silent mode behavior private final int mPlatformType; Loading Loading @@ -946,6 +952,8 @@ public class AudioService extends IAudioService.Stub private final LoudnessCodecHelper mLoudnessCodecHelper; private final HardeningEnforcer mHardeningEnforcer; private final Object mSupportedSystemUsagesLock = new Object(); @GuardedBy("mSupportedSystemUsagesLock") private @AttributeSystemUsage int[] mSupportedSystemUsages = Loading Loading @@ -1322,6 +1330,8 @@ public class AudioService extends IAudioService.Stub mDisplayManager = context.getSystemService(DisplayManager.class); mMusicFxHelper = new MusicFxHelper(mContext, mAudioHandler); mHardeningEnforcer = new HardeningEnforcer(mContext, isPlatformAutomotive()); } private void initVolumeStreamStates() { Loading Loading @@ -1393,7 +1403,6 @@ public class AudioService extends IAudioService.Stub // check on volume initialization checkVolumeRangeInitialization("AudioService()"); } private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener = Loading @@ -1406,6 +1415,14 @@ public class AudioService extends IAudioService.Stub } }; private MediaSessionManager getMediaSessionManager() { if (mMediaSessionManager == null) { mMediaSessionManager = (MediaSessionManager) mContext .getSystemService(Context.MEDIA_SESSION_SERVICE); } return mMediaSessionManager; } /** * Initialize intent receives and settings observers for this service. * Must be called after createStreamStates() as the handling of some events Loading Loading @@ -3434,6 +3451,10 @@ public class AudioService extends IAudioService.Stub * Part of service interface, check permissions here */ public void adjustStreamVolumeWithAttribution(int streamType, int direction, int flags, String callingPackage, String attributionTag) { if (mHardeningEnforcer.blockVolumeMethod( HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_STREAM_VOLUME)) { return; } if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) { Log.w(TAG, "Trying to call adjustStreamVolume() for a11y without" + "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage); Loading Loading @@ -4214,6 +4235,10 @@ public class AudioService extends IAudioService.Stub * Part of service interface, check permissions here */ public void setStreamVolumeWithAttribution(int streamType, int index, int flags, String callingPackage, String attributionTag) { if (mHardeningEnforcer.blockVolumeMethod( HardeningEnforcer.METHOD_AUDIO_MANAGER_SET_STREAM_VOLUME)) { return; } setStreamVolumeWithAttributionInt(streamType, index, flags, /*device*/ null, callingPackage, attributionTag, true /*canChangeMuteAndUpdateController*/); } Loading Loading @@ -4457,6 +4482,18 @@ public class AudioService extends IAudioService.Stub null /* playbackConfigs */, configs /* recordConfigs */); } private void dumpFlags(PrintWriter pw) { pw.println("\nFun with Flags: "); pw.println("\tandroid.media.audio.Flags.autoPublicVolumeApiHardening:" + autoPublicVolumeApiHardening()); pw.println("\tandroid.media.audio.Flags.focusFreezeTestApi:" + focusFreezeTestApi()); pw.println("\tcom.android.media.audio.Flags.bluetoothMacAddressAnonymization:" + bluetoothMacAddressAnonymization()); pw.println("\tcom.android.media.audio.Flags.disablePrescaleAbsoluteVolume:" + disablePrescaleAbsoluteVolume()); } private void dumpAudioMode(PrintWriter pw) { pw.println("\nAudio mode: "); pw.println("- Requested mode = " + AudioSystem.modeToString(getMode())); Loading Loading @@ -5081,6 +5118,7 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#setMasterMute(boolean, int) */ public void setMasterMute(boolean mute, int flags, String callingPackage, int userId, String attributionTag) { super.setMasterMute_enforcePermission(); setMasterMuteInternal(mute, flags, callingPackage, Loading Loading @@ -5450,6 +5488,10 @@ public class AudioService extends IAudioService.Stub } public void setRingerModeExternal(int ringerMode, String caller) { if (mHardeningEnforcer.blockVolumeMethod( HardeningEnforcer.METHOD_AUDIO_MANAGER_SET_RINGER_MODE)) { return; } if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode) && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) { throw new SecurityException("Not allowed to change Do Not Disturb state"); Loading Loading @@ -6202,6 +6244,35 @@ public class AudioService extends IAudioService.Stub AudioDeviceVolumeManager.ADJUST_MODE_NORMAL); } /** * @see AudioManager#adjustVolume(int, int) * This method is redirected from AudioManager to AudioService for API hardening rules * enforcement then to MediaSession for implementation. */ @Override public void adjustVolume(int direction, int flags) { if (mHardeningEnforcer.blockVolumeMethod( HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_VOLUME)) { return; } getMediaSessionManager().dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags); } /** * @see AudioManager#adjustSuggestedStreamVolume(int, int, int) * This method is redirected from AudioManager to AudioService for API hardening rules * enforcement then to MediaSession for implementation. */ @Override public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { if (mHardeningEnforcer.blockVolumeMethod( HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_SUGGESTED_STREAM_VOLUME)) { return; } getMediaSessionManager().dispatchAdjustVolume(suggestedStreamType, direction, flags); } /** @see AudioManager#setStreamVolumeForUid(int, int, int, String, int, int, int) */ @Override public void setStreamVolumeForUid(int streamType, int index, int flags, Loading Loading @@ -11405,6 +11476,7 @@ public class AudioService extends IAudioService.Stub } else { pw.println("\nMessage handler is null"); } dumpFlags(pw); mMediaFocusControl.dump(pw); dumpStreamStates(pw); dumpVolumeGroups(pw); Loading services/core/java/com/android/server/audio/HardeningEnforcer.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.audio; import static android.media.audio.Flags.autoPublicVolumeApiHardening; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.media.AudioManager; import android.os.Binder; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; /** * Class to encapsulate all audio API hardening operations */ public class HardeningEnforcer { private static final String TAG = "AS.HardeningEnforcer"; final Context mContext; final boolean mIsAutomotive; /** * Matches calls from {@link AudioManager#setStreamVolume(int, int, int)} */ public static final int METHOD_AUDIO_MANAGER_SET_STREAM_VOLUME = 100; /** * Matches calls from {@link AudioManager#adjustVolume(int, int)} */ public static final int METHOD_AUDIO_MANAGER_ADJUST_VOLUME = 101; /** * Matches calls from {@link AudioManager#adjustSuggestedStreamVolume(int, int, int)} */ public static final int METHOD_AUDIO_MANAGER_ADJUST_SUGGESTED_STREAM_VOLUME = 102; /** * Matches calls from {@link AudioManager#adjustStreamVolume(int, int, int)} */ public static final int METHOD_AUDIO_MANAGER_ADJUST_STREAM_VOLUME = 103; /** * Matches calls from {@link AudioManager#setRingerMode(int)} */ public static final int METHOD_AUDIO_MANAGER_SET_RINGER_MODE = 200; public HardeningEnforcer(Context ctxt, boolean isAutomotive) { mContext = ctxt; mIsAutomotive = isAutomotive; } /** * Checks whether the call in the current thread should be allowed or blocked * @param volumeMethod name of the method to check, for logging purposes * @return false if the method call is allowed, true if it should be a no-op */ protected boolean blockVolumeMethod(int volumeMethod) { // for Auto, volume methods require MODIFY_AUDIO_SETTINGS_PRIVILEGED if (mIsAutomotive) { if (!autoPublicVolumeApiHardening()) { // automotive hardening flag disabled, no blocking on auto return false; } if (mContext.checkCallingOrSelfPermission( Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) == PackageManager.PERMISSION_GRANTED) { return false; } if (Binder.getCallingUid() < UserHandle.AID_APP_START) { return false; } // TODO metrics? // TODO log for audio dumpsys? Log.e(TAG, "Preventing volume method " + volumeMethod + " for " + getPackNameForUid(Binder.getCallingUid())); return true; } // not blocking return false; } private String getPackNameForUid(int uid) { final long token = Binder.clearCallingIdentity(); try { final String[] names = mContext.getPackageManager().getPackagesForUid(uid); if (names == null || names.length == 0 || TextUtils.isEmpty(names[0])) { return "[" + uid + "]"; } return names[0]; } finally { Binder.restoreCallingIdentity(token); } } } Loading
media/java/android/media/AudioManager.java +52 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.media; import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT; import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.media.audio.Flags.autoPublicVolumeApiHardening; import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API; import android.Manifest; Loading Loading @@ -49,6 +50,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.media.AudioAttributes.AttributeSystemUsage; import android.media.CallbackUtil.ListenerInfo; import android.media.audiopolicy.AudioPolicy; Loading Loading @@ -901,6 +903,7 @@ public class AudioManager { @UnsupportedAppUsage public AudioManager(Context context) { setContext(context); initPlatform(); } private Context getContext() { Loading @@ -914,6 +917,9 @@ public class AudioManager { } private void setContext(Context context) { if (context == null) { return; } mOriginalContextDeviceId = context.getDeviceId(); mApplicationContext = context.getApplicationContext(); if (mApplicationContext != null) { Loading Loading @@ -1063,9 +1069,18 @@ public class AudioManager { * @see #isVolumeFixed() */ public void adjustVolume(int direction, @PublicVolumeFlags int flags) { if (applyAutoHardening()) { final IAudioService service = getService(); try { service.adjustVolume(direction, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags); } } /** * Adjusts the volume of the most relevant stream, or the given fallback Loading Loading @@ -1093,9 +1108,18 @@ public class AudioManager { */ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, @PublicVolumeFlags int flags) { if (applyAutoHardening()) { final IAudioService service = getService(); try { service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags); } } /** @hide */ @UnsupportedAppUsage Loading Loading @@ -9969,6 +9993,30 @@ public class AudioManager { } } //==================================================================== // Flag related utilities private boolean mIsAutomotive = false; private void initPlatform() { try { final Context context = getContext(); if (context != null) { mIsAutomotive = context.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); } } catch (Exception e) { Log.e(TAG, "Error querying system feature for AUTOMOTIVE", e); } } private boolean applyAutoHardening() { if (mIsAutomotive && autoPublicVolumeApiHardening()) { return true; } return false; } //--------------------------------------------------------- // Inner classes //-------------------- Loading
media/java/android/media/IAudioService.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -500,6 +500,10 @@ interface IAudioService { in String packageName, int uid, int pid, in UserHandle userHandle, int targetSdkVersion); oneway void adjustVolume(int direction, int flags); oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags); boolean isMusicActive(in boolean remotely); int getDeviceMaskForStream(in int streamType); Loading
services/core/java/com/android/server/audio/AudioService.java +73 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.server.audio; import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED; import static android.app.BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT; import static android.media.audio.Flags.autoPublicVolumeApiHardening; import static android.media.audio.Flags.focusFreezeTestApi; import static android.media.AudioDeviceInfo.TYPE_BLE_HEADSET; import static android.media.AudioDeviceInfo.TYPE_BLE_SPEAKER; import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP; Loading Loading @@ -157,6 +159,7 @@ import android.media.permission.SafeCloseable; import android.media.projection.IMediaProjection; import android.media.projection.IMediaProjectionCallback; import android.media.projection.IMediaProjectionManager; import android.media.session.MediaSessionManager; import android.net.Uri; import android.os.Binder; import android.os.Build; Loading Loading @@ -314,6 +317,9 @@ public class AudioService extends IAudioService.Stub private final ContentResolver mContentResolver; private final AppOpsManager mAppOps; /** do not use directly, use getMediaSessionManager() which handles lazy initialization */ @Nullable private volatile MediaSessionManager mMediaSessionManager; // the platform type affects volume and silent mode behavior private final int mPlatformType; Loading Loading @@ -946,6 +952,8 @@ public class AudioService extends IAudioService.Stub private final LoudnessCodecHelper mLoudnessCodecHelper; private final HardeningEnforcer mHardeningEnforcer; private final Object mSupportedSystemUsagesLock = new Object(); @GuardedBy("mSupportedSystemUsagesLock") private @AttributeSystemUsage int[] mSupportedSystemUsages = Loading Loading @@ -1322,6 +1330,8 @@ public class AudioService extends IAudioService.Stub mDisplayManager = context.getSystemService(DisplayManager.class); mMusicFxHelper = new MusicFxHelper(mContext, mAudioHandler); mHardeningEnforcer = new HardeningEnforcer(mContext, isPlatformAutomotive()); } private void initVolumeStreamStates() { Loading Loading @@ -1393,7 +1403,6 @@ public class AudioService extends IAudioService.Stub // check on volume initialization checkVolumeRangeInitialization("AudioService()"); } private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener = Loading @@ -1406,6 +1415,14 @@ public class AudioService extends IAudioService.Stub } }; private MediaSessionManager getMediaSessionManager() { if (mMediaSessionManager == null) { mMediaSessionManager = (MediaSessionManager) mContext .getSystemService(Context.MEDIA_SESSION_SERVICE); } return mMediaSessionManager; } /** * Initialize intent receives and settings observers for this service. * Must be called after createStreamStates() as the handling of some events Loading Loading @@ -3434,6 +3451,10 @@ public class AudioService extends IAudioService.Stub * Part of service interface, check permissions here */ public void adjustStreamVolumeWithAttribution(int streamType, int direction, int flags, String callingPackage, String attributionTag) { if (mHardeningEnforcer.blockVolumeMethod( HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_STREAM_VOLUME)) { return; } if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) { Log.w(TAG, "Trying to call adjustStreamVolume() for a11y without" + "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage); Loading Loading @@ -4214,6 +4235,10 @@ public class AudioService extends IAudioService.Stub * Part of service interface, check permissions here */ public void setStreamVolumeWithAttribution(int streamType, int index, int flags, String callingPackage, String attributionTag) { if (mHardeningEnforcer.blockVolumeMethod( HardeningEnforcer.METHOD_AUDIO_MANAGER_SET_STREAM_VOLUME)) { return; } setStreamVolumeWithAttributionInt(streamType, index, flags, /*device*/ null, callingPackage, attributionTag, true /*canChangeMuteAndUpdateController*/); } Loading Loading @@ -4457,6 +4482,18 @@ public class AudioService extends IAudioService.Stub null /* playbackConfigs */, configs /* recordConfigs */); } private void dumpFlags(PrintWriter pw) { pw.println("\nFun with Flags: "); pw.println("\tandroid.media.audio.Flags.autoPublicVolumeApiHardening:" + autoPublicVolumeApiHardening()); pw.println("\tandroid.media.audio.Flags.focusFreezeTestApi:" + focusFreezeTestApi()); pw.println("\tcom.android.media.audio.Flags.bluetoothMacAddressAnonymization:" + bluetoothMacAddressAnonymization()); pw.println("\tcom.android.media.audio.Flags.disablePrescaleAbsoluteVolume:" + disablePrescaleAbsoluteVolume()); } private void dumpAudioMode(PrintWriter pw) { pw.println("\nAudio mode: "); pw.println("- Requested mode = " + AudioSystem.modeToString(getMode())); Loading Loading @@ -5081,6 +5118,7 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#setMasterMute(boolean, int) */ public void setMasterMute(boolean mute, int flags, String callingPackage, int userId, String attributionTag) { super.setMasterMute_enforcePermission(); setMasterMuteInternal(mute, flags, callingPackage, Loading Loading @@ -5450,6 +5488,10 @@ public class AudioService extends IAudioService.Stub } public void setRingerModeExternal(int ringerMode, String caller) { if (mHardeningEnforcer.blockVolumeMethod( HardeningEnforcer.METHOD_AUDIO_MANAGER_SET_RINGER_MODE)) { return; } if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode) && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) { throw new SecurityException("Not allowed to change Do Not Disturb state"); Loading Loading @@ -6202,6 +6244,35 @@ public class AudioService extends IAudioService.Stub AudioDeviceVolumeManager.ADJUST_MODE_NORMAL); } /** * @see AudioManager#adjustVolume(int, int) * This method is redirected from AudioManager to AudioService for API hardening rules * enforcement then to MediaSession for implementation. */ @Override public void adjustVolume(int direction, int flags) { if (mHardeningEnforcer.blockVolumeMethod( HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_VOLUME)) { return; } getMediaSessionManager().dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags); } /** * @see AudioManager#adjustSuggestedStreamVolume(int, int, int) * This method is redirected from AudioManager to AudioService for API hardening rules * enforcement then to MediaSession for implementation. */ @Override public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { if (mHardeningEnforcer.blockVolumeMethod( HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_SUGGESTED_STREAM_VOLUME)) { return; } getMediaSessionManager().dispatchAdjustVolume(suggestedStreamType, direction, flags); } /** @see AudioManager#setStreamVolumeForUid(int, int, int, String, int, int, int) */ @Override public void setStreamVolumeForUid(int streamType, int index, int flags, Loading Loading @@ -11405,6 +11476,7 @@ public class AudioService extends IAudioService.Stub } else { pw.println("\nMessage handler is null"); } dumpFlags(pw); mMediaFocusControl.dump(pw); dumpStreamStates(pw); dumpVolumeGroups(pw); Loading
services/core/java/com/android/server/audio/HardeningEnforcer.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.audio; import static android.media.audio.Flags.autoPublicVolumeApiHardening; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.media.AudioManager; import android.os.Binder; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; /** * Class to encapsulate all audio API hardening operations */ public class HardeningEnforcer { private static final String TAG = "AS.HardeningEnforcer"; final Context mContext; final boolean mIsAutomotive; /** * Matches calls from {@link AudioManager#setStreamVolume(int, int, int)} */ public static final int METHOD_AUDIO_MANAGER_SET_STREAM_VOLUME = 100; /** * Matches calls from {@link AudioManager#adjustVolume(int, int)} */ public static final int METHOD_AUDIO_MANAGER_ADJUST_VOLUME = 101; /** * Matches calls from {@link AudioManager#adjustSuggestedStreamVolume(int, int, int)} */ public static final int METHOD_AUDIO_MANAGER_ADJUST_SUGGESTED_STREAM_VOLUME = 102; /** * Matches calls from {@link AudioManager#adjustStreamVolume(int, int, int)} */ public static final int METHOD_AUDIO_MANAGER_ADJUST_STREAM_VOLUME = 103; /** * Matches calls from {@link AudioManager#setRingerMode(int)} */ public static final int METHOD_AUDIO_MANAGER_SET_RINGER_MODE = 200; public HardeningEnforcer(Context ctxt, boolean isAutomotive) { mContext = ctxt; mIsAutomotive = isAutomotive; } /** * Checks whether the call in the current thread should be allowed or blocked * @param volumeMethod name of the method to check, for logging purposes * @return false if the method call is allowed, true if it should be a no-op */ protected boolean blockVolumeMethod(int volumeMethod) { // for Auto, volume methods require MODIFY_AUDIO_SETTINGS_PRIVILEGED if (mIsAutomotive) { if (!autoPublicVolumeApiHardening()) { // automotive hardening flag disabled, no blocking on auto return false; } if (mContext.checkCallingOrSelfPermission( Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) == PackageManager.PERMISSION_GRANTED) { return false; } if (Binder.getCallingUid() < UserHandle.AID_APP_START) { return false; } // TODO metrics? // TODO log for audio dumpsys? Log.e(TAG, "Preventing volume method " + volumeMethod + " for " + getPackNameForUid(Binder.getCallingUid())); return true; } // not blocking return false; } private String getPackNameForUid(int uid) { final long token = Binder.clearCallingIdentity(); try { final String[] names = mContext.getPackageManager().getPackagesForUid(uid); if (names == null || names.length == 0 || TextUtils.isEmpty(names[0])) { return "[" + uid + "]"; } return names[0]; } finally { Binder.restoreCallingIdentity(token); } } }