Loading media/java/android/media/AudioDeviceVolumeManager.java +18 −2 Original line number Diff line number Diff line Loading @@ -61,10 +61,12 @@ public class AudioDeviceVolumeManager { private static IAudioService sService; private final String mPackageName; private final @NonNull String mPackageName; private final @Nullable String mAttributionTag; public AudioDeviceVolumeManager(Context context) { mPackageName = context.getApplicationContext().getOpPackageName(); mAttributionTag = context.getApplicationContext().getAttributionTag(); } /** Loading Loading @@ -287,7 +289,6 @@ public class AudioDeviceVolumeManager { * @hide * Removes a previously added listener of changes to device volume behavior. */ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE Loading @@ -298,6 +299,21 @@ public class AudioDeviceVolumeManager { "removeOnDeviceVolumeBehaviorChangedListener"); } /** * @hide * Sets the volume on the given audio device * @param vi the volume information, only stream-based volumes are supported * @param ada the device for which volume is to be modified */ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada) { try { getService().setDeviceVolume(vi, ada, mPackageName, mAttributionTag); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Return human-readable name for volume behavior * @param behavior one of the volume behaviors defined in AudioManager Loading media/java/android/media/IAudioService.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,9 @@ interface IAudioService { void setStreamVolumeWithAttribution(int streamType, int index, int flags, in String callingPackage, in String attributionTag); void setDeviceVolume(in VolumeInfo vi, in AudioDeviceAttributes ada, in String callingPackage, in String attributionTag); oneway void handleVolumeKey(in KeyEvent event, boolean isOnTv, String callingPackage, String caller); Loading services/core/java/com/android/server/audio/AudioService.java +80 −11 Original line number Diff line number Diff line Loading @@ -175,6 +175,7 @@ import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.audio.AudioServiceEvents.DeviceVolumeEvent; import com.android.server.audio.AudioServiceEvents.PhoneStateEvent; import com.android.server.audio.AudioServiceEvents.VolumeEvent; import com.android.server.pm.UserManagerInternal; Loading Loading @@ -3584,7 +3585,8 @@ public class AudioService extends IAudioService.Stub + "), do not change associated stream volume"); continue; } setStreamVolume(groupedStream, index, flags, callingPackage, callingPackage, setStreamVolume(groupedStream, index, flags, /*device*/ null, callingPackage, callingPackage, attributionTag, Binder.getCallingUid(), true /*hasModifyAudioSettings*/); } } Loading Loading @@ -3627,15 +3629,73 @@ public class AudioService extends IAudioService.Stub return AudioSystem.getMinVolumeIndexForAttributes(attr); } /** @see AudioDeviceVolumeManager#setDeviceVolume(VolumeInfo, AudioDeviceAttributes) * Part of service interface, check permissions and parameters here */ public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada, @NonNull String callingPackage, @Nullable String attributionTag) { enforceModifyAudioRoutingPermission(); Objects.requireNonNull(vi); Objects.requireNonNull(ada); Objects.requireNonNull(callingPackage); if (!vi.hasStreamType()) { Log.e(TAG, "Unsupported non-stream type based VolumeInfo", new Exception()); return; } int index = vi.getVolumeIndex(); if (index == VolumeInfo.INDEX_NOT_SET) { throw new IllegalArgumentException("changing device volume requires a volume index"); } if (vi.getMinVolumeIndex() == VolumeInfo.INDEX_NOT_SET || vi.getMaxVolumeIndex() == VolumeInfo.INDEX_NOT_SET) { // assume index meant to be in stream type range, validate if ((index * 10) < mStreamStates[vi.getStreamType()].getMinIndex() || (index * 10) > mStreamStates[vi.getStreamType()].getMaxIndex()) { throw new IllegalArgumentException("invalid volume index " + index + " not between min/max for stream " + vi.getStreamType()); } } else { // check if index needs to be rescaled final int min = (mStreamStates[vi.getStreamType()].getMinIndex() + 5) / 10; final int max = (mStreamStates[vi.getStreamType()].getMaxIndex() + 5) / 10; if (vi.getMinVolumeIndex() != min || vi.getMaxVolumeIndex() != max) { index = rescaleIndex(index, /*srcMin*/ vi.getMinVolumeIndex(), /*srcMax*/ vi.getMaxVolumeIndex(), /*dstMin*/ min, /*dstMax*/ max); } } setStreamVolumeWithAttributionInt(vi.getStreamType(), index, /*flags*/ 0, ada, callingPackage, attributionTag); } /** Retain API for unsupported app usage */ public void setStreamVolume(int streamType, int index, int flags, String callingPackage) { setStreamVolumeWithAttribution(streamType, index, flags, callingPackage, null); setStreamVolumeWithAttribution(streamType, index, flags, callingPackage, /*attributionTag*/ null); } /** @see AudioManager#setStreamVolume(int, int, int) * Part of service interface, check permissions here */ public void setStreamVolumeWithAttribution(int streamType, int index, int flags, String callingPackage, String attributionTag) { setStreamVolumeWithAttributionInt(streamType, index, flags, /*device*/ null, callingPackage, attributionTag); } /** * Internal method for a stream type volume change. Can be used to change the volume on a * given device only * @param streamType the stream type whose volume is to be changed * @param index the volume index * @param flags options for volume handling * @param device null when controlling volume for the current routing, otherwise the device * for which volume is being changed * @param callingPackage client side-provided package name of caller, not to be trusted * @param attributionTag client side-provided attribution name, not to be trusted */ protected void setStreamVolumeWithAttributionInt(int streamType, int index, int flags, @Nullable AudioDeviceAttributes device, String callingPackage, String attributionTag) { if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) { Log.w(TAG, "Trying to call setStreamVolume() for a11y without" + " CHANGE_ACCESSIBILITY_VOLUME callingPackage=" + callingPackage); Loading @@ -3658,10 +3718,14 @@ public class AudioService extends IAudioService.Stub return; } sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType, index/*val1*/, flags/*val2*/, callingPackage)); setStreamVolume(streamType, index, flags, callingPackage, callingPackage, attributionTag, Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission()); final AudioEventLogger.Event event = (device == null) ? new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType, index/*val1*/, flags/*val2*/, callingPackage) : new DeviceVolumeEvent(streamType, index, device, callingPackage); sVolumeLogger.log(event); setStreamVolume(streamType, index, flags, device, callingPackage, callingPackage, attributionTag, Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission()); } /** @see AudioManager#isUltrasoundSupported() */ Loading Loading @@ -3900,11 +3964,13 @@ public class AudioService extends IAudioService.Stub } } private void setStreamVolume(int streamType, int index, int flags, String callingPackage, String caller, String attributionTag, int uid, private void setStreamVolume(int streamType, int index, int flags, @Nullable AudioDeviceAttributes ada, String callingPackage, String caller, String attributionTag, int uid, boolean hasModifyAudioSettings) { if (DEBUG_VOL) { Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index + ", dev=" + ada + ", calling=" + callingPackage + ")"); } if (mUseFixedVolume) { Loading @@ -3915,7 +3981,9 @@ public class AudioService extends IAudioService.Stub int streamTypeAlias = mStreamVolumeAlias[streamType]; VolumeStreamState streamState = mStreamStates[streamTypeAlias]; final int device = getDeviceForStream(streamType); final int device = (ada == null) ? getDeviceForStream(streamType) : ada.getInternalType(); int oldIndex; // skip a2dp absolute volume control request when the device Loading Loading @@ -5419,7 +5487,8 @@ public class AudioService extends IAudioService.Stub throw new SecurityException("Should only be called from system process"); } setStreamVolume(streamType, index, flags, packageName, packageName, null, uid, setStreamVolume(streamType, index, flags, /*device*/ null, packageName, packageName, null, uid, hasAudioSettingsPermission(uid, pid)); } Loading Loading @@ -7562,7 +7631,7 @@ public class AudioService extends IAudioService.Stub && !isFullyMuted()) { index = 1; } AudioSystem.setStreamVolumeIndexAS(mStreamType, index, device); mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, device); } // must be called while synchronized VolumeStreamState.class Loading services/core/java/com/android/server/audio/AudioServiceEvents.java +39 −0 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ package com.android.server.audio; import android.annotation.NonNull; import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioManager; import android.media.AudioSystem; import android.media.MediaMetrics; Loading Loading @@ -145,6 +147,43 @@ public class AudioServiceEvents { } } static final class DeviceVolumeEvent extends AudioEventLogger.Event { final int mStream; final int mVolIndex; final String mDeviceNativeType; final String mDeviceAddress; final String mCaller; DeviceVolumeEvent(int streamType, int index, @NonNull AudioDeviceAttributes device, String callingPackage) { mStream = streamType; mVolIndex = index; mDeviceNativeType = "0x" + Integer.toHexString(device.getInternalType()); mDeviceAddress = device.getAddress(); mCaller = callingPackage; // log metrics new MediaMetrics.Item(MediaMetrics.Name.AUDIO_VOLUME_EVENT) .set(MediaMetrics.Property.EVENT, "setDeviceVolume") .set(MediaMetrics.Property.STREAM_TYPE, AudioSystem.streamToString(mStream)) .set(MediaMetrics.Property.INDEX, mVolIndex) .set(MediaMetrics.Property.DEVICE, mDeviceNativeType) .set(MediaMetrics.Property.ADDRESS, mDeviceAddress) .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller) .record(); } @Override public String eventToString() { return new StringBuilder("setDeviceVolume(stream:") .append(AudioSystem.streamToString(mStream)) .append(" index:").append(mVolIndex) .append(" device:").append(mDeviceNativeType) .append(" addr:").append(mDeviceAddress) .append(") from ").append(mCaller).toString(); } } final static class VolumeEvent extends AudioEventLogger.Event { static final int VOL_ADJUST_SUGG_VOL = 0; static final int VOL_ADJUST_STREAM_VOL = 1; Loading services/core/java/com/android/server/audio/AudioSystemAdapter.java +11 −0 Original line number Diff line number Diff line Loading @@ -386,6 +386,17 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback, return AudioSystem.isStreamActiveRemotely(stream, inPastMs); } /** * Same as {@link AudioSystem#setStreamVolumeIndexAS(int, int, int)} * @param stream * @param index * @param device * @return */ public int setStreamVolumeIndexAS(int stream, int index, int device) { return AudioSystem.setStreamVolumeIndexAS(stream, index, device); } /** * Same as {@link AudioSystem#setPhoneState(int, int)} * @param state Loading Loading
media/java/android/media/AudioDeviceVolumeManager.java +18 −2 Original line number Diff line number Diff line Loading @@ -61,10 +61,12 @@ public class AudioDeviceVolumeManager { private static IAudioService sService; private final String mPackageName; private final @NonNull String mPackageName; private final @Nullable String mAttributionTag; public AudioDeviceVolumeManager(Context context) { mPackageName = context.getApplicationContext().getOpPackageName(); mAttributionTag = context.getApplicationContext().getAttributionTag(); } /** Loading Loading @@ -287,7 +289,6 @@ public class AudioDeviceVolumeManager { * @hide * Removes a previously added listener of changes to device volume behavior. */ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE Loading @@ -298,6 +299,21 @@ public class AudioDeviceVolumeManager { "removeOnDeviceVolumeBehaviorChangedListener"); } /** * @hide * Sets the volume on the given audio device * @param vi the volume information, only stream-based volumes are supported * @param ada the device for which volume is to be modified */ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada) { try { getService().setDeviceVolume(vi, ada, mPackageName, mAttributionTag); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Return human-readable name for volume behavior * @param behavior one of the volume behaviors defined in AudioManager Loading
media/java/android/media/IAudioService.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,9 @@ interface IAudioService { void setStreamVolumeWithAttribution(int streamType, int index, int flags, in String callingPackage, in String attributionTag); void setDeviceVolume(in VolumeInfo vi, in AudioDeviceAttributes ada, in String callingPackage, in String attributionTag); oneway void handleVolumeKey(in KeyEvent event, boolean isOnTv, String callingPackage, String caller); Loading
services/core/java/com/android/server/audio/AudioService.java +80 −11 Original line number Diff line number Diff line Loading @@ -175,6 +175,7 @@ import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.audio.AudioServiceEvents.DeviceVolumeEvent; import com.android.server.audio.AudioServiceEvents.PhoneStateEvent; import com.android.server.audio.AudioServiceEvents.VolumeEvent; import com.android.server.pm.UserManagerInternal; Loading Loading @@ -3584,7 +3585,8 @@ public class AudioService extends IAudioService.Stub + "), do not change associated stream volume"); continue; } setStreamVolume(groupedStream, index, flags, callingPackage, callingPackage, setStreamVolume(groupedStream, index, flags, /*device*/ null, callingPackage, callingPackage, attributionTag, Binder.getCallingUid(), true /*hasModifyAudioSettings*/); } } Loading Loading @@ -3627,15 +3629,73 @@ public class AudioService extends IAudioService.Stub return AudioSystem.getMinVolumeIndexForAttributes(attr); } /** @see AudioDeviceVolumeManager#setDeviceVolume(VolumeInfo, AudioDeviceAttributes) * Part of service interface, check permissions and parameters here */ public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada, @NonNull String callingPackage, @Nullable String attributionTag) { enforceModifyAudioRoutingPermission(); Objects.requireNonNull(vi); Objects.requireNonNull(ada); Objects.requireNonNull(callingPackage); if (!vi.hasStreamType()) { Log.e(TAG, "Unsupported non-stream type based VolumeInfo", new Exception()); return; } int index = vi.getVolumeIndex(); if (index == VolumeInfo.INDEX_NOT_SET) { throw new IllegalArgumentException("changing device volume requires a volume index"); } if (vi.getMinVolumeIndex() == VolumeInfo.INDEX_NOT_SET || vi.getMaxVolumeIndex() == VolumeInfo.INDEX_NOT_SET) { // assume index meant to be in stream type range, validate if ((index * 10) < mStreamStates[vi.getStreamType()].getMinIndex() || (index * 10) > mStreamStates[vi.getStreamType()].getMaxIndex()) { throw new IllegalArgumentException("invalid volume index " + index + " not between min/max for stream " + vi.getStreamType()); } } else { // check if index needs to be rescaled final int min = (mStreamStates[vi.getStreamType()].getMinIndex() + 5) / 10; final int max = (mStreamStates[vi.getStreamType()].getMaxIndex() + 5) / 10; if (vi.getMinVolumeIndex() != min || vi.getMaxVolumeIndex() != max) { index = rescaleIndex(index, /*srcMin*/ vi.getMinVolumeIndex(), /*srcMax*/ vi.getMaxVolumeIndex(), /*dstMin*/ min, /*dstMax*/ max); } } setStreamVolumeWithAttributionInt(vi.getStreamType(), index, /*flags*/ 0, ada, callingPackage, attributionTag); } /** Retain API for unsupported app usage */ public void setStreamVolume(int streamType, int index, int flags, String callingPackage) { setStreamVolumeWithAttribution(streamType, index, flags, callingPackage, null); setStreamVolumeWithAttribution(streamType, index, flags, callingPackage, /*attributionTag*/ null); } /** @see AudioManager#setStreamVolume(int, int, int) * Part of service interface, check permissions here */ public void setStreamVolumeWithAttribution(int streamType, int index, int flags, String callingPackage, String attributionTag) { setStreamVolumeWithAttributionInt(streamType, index, flags, /*device*/ null, callingPackage, attributionTag); } /** * Internal method for a stream type volume change. Can be used to change the volume on a * given device only * @param streamType the stream type whose volume is to be changed * @param index the volume index * @param flags options for volume handling * @param device null when controlling volume for the current routing, otherwise the device * for which volume is being changed * @param callingPackage client side-provided package name of caller, not to be trusted * @param attributionTag client side-provided attribution name, not to be trusted */ protected void setStreamVolumeWithAttributionInt(int streamType, int index, int flags, @Nullable AudioDeviceAttributes device, String callingPackage, String attributionTag) { if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) { Log.w(TAG, "Trying to call setStreamVolume() for a11y without" + " CHANGE_ACCESSIBILITY_VOLUME callingPackage=" + callingPackage); Loading @@ -3658,10 +3718,14 @@ public class AudioService extends IAudioService.Stub return; } sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType, index/*val1*/, flags/*val2*/, callingPackage)); setStreamVolume(streamType, index, flags, callingPackage, callingPackage, attributionTag, Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission()); final AudioEventLogger.Event event = (device == null) ? new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType, index/*val1*/, flags/*val2*/, callingPackage) : new DeviceVolumeEvent(streamType, index, device, callingPackage); sVolumeLogger.log(event); setStreamVolume(streamType, index, flags, device, callingPackage, callingPackage, attributionTag, Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission()); } /** @see AudioManager#isUltrasoundSupported() */ Loading Loading @@ -3900,11 +3964,13 @@ public class AudioService extends IAudioService.Stub } } private void setStreamVolume(int streamType, int index, int flags, String callingPackage, String caller, String attributionTag, int uid, private void setStreamVolume(int streamType, int index, int flags, @Nullable AudioDeviceAttributes ada, String callingPackage, String caller, String attributionTag, int uid, boolean hasModifyAudioSettings) { if (DEBUG_VOL) { Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index + ", dev=" + ada + ", calling=" + callingPackage + ")"); } if (mUseFixedVolume) { Loading @@ -3915,7 +3981,9 @@ public class AudioService extends IAudioService.Stub int streamTypeAlias = mStreamVolumeAlias[streamType]; VolumeStreamState streamState = mStreamStates[streamTypeAlias]; final int device = getDeviceForStream(streamType); final int device = (ada == null) ? getDeviceForStream(streamType) : ada.getInternalType(); int oldIndex; // skip a2dp absolute volume control request when the device Loading Loading @@ -5419,7 +5487,8 @@ public class AudioService extends IAudioService.Stub throw new SecurityException("Should only be called from system process"); } setStreamVolume(streamType, index, flags, packageName, packageName, null, uid, setStreamVolume(streamType, index, flags, /*device*/ null, packageName, packageName, null, uid, hasAudioSettingsPermission(uid, pid)); } Loading Loading @@ -7562,7 +7631,7 @@ public class AudioService extends IAudioService.Stub && !isFullyMuted()) { index = 1; } AudioSystem.setStreamVolumeIndexAS(mStreamType, index, device); mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, device); } // must be called while synchronized VolumeStreamState.class Loading
services/core/java/com/android/server/audio/AudioServiceEvents.java +39 −0 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ package com.android.server.audio; import android.annotation.NonNull; import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioManager; import android.media.AudioSystem; import android.media.MediaMetrics; Loading Loading @@ -145,6 +147,43 @@ public class AudioServiceEvents { } } static final class DeviceVolumeEvent extends AudioEventLogger.Event { final int mStream; final int mVolIndex; final String mDeviceNativeType; final String mDeviceAddress; final String mCaller; DeviceVolumeEvent(int streamType, int index, @NonNull AudioDeviceAttributes device, String callingPackage) { mStream = streamType; mVolIndex = index; mDeviceNativeType = "0x" + Integer.toHexString(device.getInternalType()); mDeviceAddress = device.getAddress(); mCaller = callingPackage; // log metrics new MediaMetrics.Item(MediaMetrics.Name.AUDIO_VOLUME_EVENT) .set(MediaMetrics.Property.EVENT, "setDeviceVolume") .set(MediaMetrics.Property.STREAM_TYPE, AudioSystem.streamToString(mStream)) .set(MediaMetrics.Property.INDEX, mVolIndex) .set(MediaMetrics.Property.DEVICE, mDeviceNativeType) .set(MediaMetrics.Property.ADDRESS, mDeviceAddress) .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller) .record(); } @Override public String eventToString() { return new StringBuilder("setDeviceVolume(stream:") .append(AudioSystem.streamToString(mStream)) .append(" index:").append(mVolIndex) .append(" device:").append(mDeviceNativeType) .append(" addr:").append(mDeviceAddress) .append(") from ").append(mCaller).toString(); } } final static class VolumeEvent extends AudioEventLogger.Event { static final int VOL_ADJUST_SUGG_VOL = 0; static final int VOL_ADJUST_STREAM_VOL = 1; Loading
services/core/java/com/android/server/audio/AudioSystemAdapter.java +11 −0 Original line number Diff line number Diff line Loading @@ -386,6 +386,17 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback, return AudioSystem.isStreamActiveRemotely(stream, inPastMs); } /** * Same as {@link AudioSystem#setStreamVolumeIndexAS(int, int, int)} * @param stream * @param index * @param device * @return */ public int setStreamVolumeIndexAS(int stream, int index, int device) { return AudioSystem.setStreamVolumeIndexAS(stream, index, device); } /** * Same as {@link AudioSystem#setPhoneState(int, int)} * @param state Loading