setDeviceVolume: better logs, clears routing cache

When a call to setDeviceVolume is received, clear the
  AudioSystemAdapter cache for the AudioAttributes to
  audio device. This will eliminate any chance of the
  cache being stale when the evaluation of whether to
  send the VOLUME_CHANGED_ACTION intent is performed.
Clean up log calls to setDeviceVolume, use a dedicated
  logger event, and also log the current device selected by
  getDevicesForStream.
Don't send volume update to VolumeController (sysUI) when a
  device was specified (== call comes from setDeviceVolume).
Fix code path in AudioDeviceBroker where its calls to
  AudioSystem.setForceUse were going directly to
  AudioSystem, instead of going through the adapter (which
  causes a cache clear, whereas it didn't in Broker). This
  is done by injecting into AudioDeviceBroker the same
  AudioSystemAdapter that AudioService uses.
Fix AudioService's obsolete use of ANALOG_DOCK, replaced
  by DIGITAL_DOCK.

Bug: 264302812
Bug: 271473257
Test: atest android.media.audio.cts.AudioDeviceVolumeManagerTest#testSetGetVolume
Change-Id: Ibfa002b51f02302686853a8dea562e75d12d8949
This commit is contained in:
Jean-Michel Trivi
2023-01-06 05:18:04 +00:00
parent 011d00e117
commit ed96743724
5 changed files with 79 additions and 18 deletions

View File

@@ -85,6 +85,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private final @NonNull AudioService mAudioService;
private final @NonNull Context mContext;
private final @NonNull AudioSystemAdapter mAudioSystem;
/** ID for Communication strategy retrieved form audio policy manager */
private int mCommunicationStrategyId = -1;
@@ -159,12 +160,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
public static final long USE_SET_COMMUNICATION_DEVICE = 243827847L;
//-------------------------------------------------------------------
/*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) {
/*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service,
@NonNull AudioSystemAdapter audioSystem) {
mContext = context;
mAudioService = service;
mBtHelper = new BtHelper(this);
mDeviceInventory = new AudioDeviceInventory(this);
mSystemServer = SystemServerAdapter.getDefaultAdapter(mContext);
mAudioSystem = audioSystem;
init();
}
@@ -173,12 +176,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
* in system_server */
AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service,
@NonNull AudioDeviceInventory mockDeviceInventory,
@NonNull SystemServerAdapter mockSystemServer) {
@NonNull SystemServerAdapter mockSystemServer,
@NonNull AudioSystemAdapter audioSystem) {
mContext = context;
mAudioService = service;
mBtHelper = new BtHelper(this);
mDeviceInventory = mockDeviceInventory;
mSystemServer = mockSystemServer;
mAudioSystem = audioSystem;
init();
}
@@ -540,7 +545,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
AudioAttributes attr =
AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(
AudioSystem.STREAM_VOICE_CALL);
List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(
List<AudioDeviceAttributes> devices = mAudioSystem.getDevicesForAttributes(
attr, false /* forVolume */);
if (devices.isEmpty()) {
if (mAudioService.isPlatformVoice()) {
@@ -1493,7 +1498,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
Log.v(TAG, "onSetForceUse(useCase<" + useCase + ">, config<" + config + ">, fromA2dp<"
+ fromA2dp + ">, eventSource<" + eventSource + ">)");
}
AudioSystem.setForceUse(useCase, config);
mAudioSystem.setForceUse(useCase, config);
}
private void onSendBecomingNoisyIntent() {

View File

@@ -199,6 +199,7 @@ 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.VolChangedBroadcastEvent;
import com.android.server.audio.AudioServiceEvents.VolumeEvent;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
@@ -1214,7 +1215,7 @@ public class AudioService extends IAudioService.Stub
mUseFixedVolume = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useFixedVolume);
mDeviceBroker = new AudioDeviceBroker(mContext, this);
mDeviceBroker = new AudioDeviceBroker(mContext, this, mAudioSystem);
mRecordMonitor = new RecordingActivityMonitor(mContext);
mRecordMonitor.registerRecordingCallback(mVoiceRecordingActivityMonitor, true);
@@ -1687,7 +1688,7 @@ public class AudioService extends IAudioService.Stub
synchronized (mSettingsLock) {
final int forDock = mDockAudioMediaEnabled ?
AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE;
AudioSystem.FORCE_DIGITAL_DOCK : AudioSystem.FORCE_NONE;
mDeviceBroker.setForceUse_Async(AudioSystem.FOR_DOCK, forDock, "onAudioServerDied");
sendEncodedSurroundMode(mContentResolver, "onAudioServerDied");
sendEnabledSurroundFormats(mContentResolver, true);
@@ -2323,9 +2324,10 @@ public class AudioService extends IAudioService.Stub
SENDMSG_QUEUE,
AudioSystem.FOR_DOCK,
mDockAudioMediaEnabled ?
AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
AudioSystem.FORCE_DIGITAL_DOCK : AudioSystem.FORCE_NONE,
new String("readDockAudioSettings"),
0);
}
@@ -3972,13 +3974,25 @@ public class AudioService extends IAudioService.Stub
Log.e(TAG, "Unsupported non-stream type based VolumeInfo", new Exception());
return;
}
int index = vi.getVolumeIndex();
if (index == VolumeInfo.INDEX_NOT_SET && !vi.hasMuteCommand()) {
throw new IllegalArgumentException(
"changing device volume requires a volume index or mute command");
}
// TODO handle unmuting if current audio device
// force a cache clear to force reevaluating stream type to audio device selection
// that can interfere with the sending of the VOLUME_CHANGED_ACTION intent
mAudioSystem.clearRoutingCache();
// log the current device that will be used when evaluating the sending of the
// VOLUME_CHANGED_ACTION intent to see if the current device is the one being modified
final int currDev = getDeviceForStream(vi.getStreamType());
AudioService.sVolumeLogger.enqueue(new DeviceVolumeEvent(vi.getStreamType(), index, ada,
currDev, callingPackage));
// TODO handle unmuting of current audio device
// if a stream is not muted but the VolumeInfo is for muting, set the volume index
// for the device to min volume
if (vi.hasMuteCommand() && vi.isMuted() && !isStreamMute(vi.getStreamType())) {
@@ -4129,11 +4143,11 @@ public class AudioService extends IAudioService.Stub
return;
}
final EventLogger.Event event = (device == null)
? new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
index/*val1*/, flags/*val2*/, callingPackage)
: new DeviceVolumeEvent(streamType, index, device, callingPackage);
sVolumeLogger.enqueue(event);
if (device == null) {
// call was already logged in setDeviceVolume()
sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
index/*val1*/, flags/*val2*/, callingPackage));
}
setStreamVolume(streamType, index, flags, device,
callingPackage, callingPackage, attributionTag,
Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission());
@@ -4547,7 +4561,11 @@ public class AudioService extends IAudioService.Stub
maybeSendSystemAudioStatusCommand(false);
}
}
sendVolumeUpdate(streamType, oldIndex, index, flags, device);
if (ada == null) {
// only non-null when coming here from setDeviceVolume
// TODO change test to check early if device is current device or not
sendVolumeUpdate(streamType, oldIndex, index, flags, device);
}
}
private void dispatchAbsoluteVolumeChanged(int streamType, AbsoluteVolumeDeviceInfo deviceInfo,
@@ -8531,6 +8549,8 @@ public class AudioService extends IAudioService.Stub
mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
mStreamVolumeAlias[mStreamType]);
AudioService.sVolumeLogger.enqueue(new VolChangedBroadcastEvent(
mStreamType, mStreamVolumeAlias[mStreamType], index));
sendBroadcastToAll(mVolumeChanged, mVolumeChangedOptions);
}
}
@@ -10807,7 +10827,7 @@ public class AudioService extends IAudioService.Stub
static final int LOG_NB_EVENTS_PHONE_STATE = 20;
static final int LOG_NB_EVENTS_DEVICE_CONNECTION = 50;
static final int LOG_NB_EVENTS_FORCE_USE = 20;
static final int LOG_NB_EVENTS_VOLUME = 40;
static final int LOG_NB_EVENTS_VOLUME = 100;
static final int LOG_NB_EVENTS_DYN_POLICY = 10;
static final int LOG_NB_EVENTS_SPATIAL = 30;
static final int LOG_NB_EVENTS_SOUND_DOSE = 30;

View File

@@ -147,19 +147,42 @@ public class AudioServiceEvents {
}
}
static final class VolChangedBroadcastEvent extends EventLogger.Event {
final int mStreamType;
final int mAliasStreamType;
final int mIndex;
VolChangedBroadcastEvent(int stream, int alias, int index) {
mStreamType = stream;
mAliasStreamType = alias;
mIndex = index;
}
@Override
public String eventToString() {
return new StringBuilder("sending VOLUME_CHANGED stream:")
.append(AudioSystem.streamToString(mStreamType))
.append(" index:").append(mIndex)
.append(" alias:").append(AudioSystem.streamToString(mAliasStreamType))
.toString();
}
}
static final class DeviceVolumeEvent extends EventLogger.Event {
final int mStream;
final int mVolIndex;
final String mDeviceNativeType;
final String mDeviceAddress;
final String mCaller;
final int mDeviceForStream;
DeviceVolumeEvent(int streamType, int index, @NonNull AudioDeviceAttributes device,
String callingPackage) {
int deviceForStream, String callingPackage) {
mStream = streamType;
mVolIndex = index;
mDeviceNativeType = "0x" + Integer.toHexString(device.getInternalType());
mDeviceAddress = device.getAddress();
mDeviceForStream = deviceForStream;
mCaller = callingPackage;
// log metrics
new MediaMetrics.Item(MediaMetrics.Name.AUDIO_VOLUME_EVENT)
@@ -180,7 +203,9 @@ public class AudioServiceEvents {
.append(" index:").append(mVolIndex)
.append(" device:").append(mDeviceNativeType)
.append(" addr:").append(mDeviceAddress)
.append(") from ").append(mCaller).toString();
.append(") from ").append(mCaller)
.append(" currDevForStream:Ox").append(Integer.toHexString(mDeviceForStream))
.toString();
}
}

View File

@@ -161,6 +161,16 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback,
}
}
/**
* Empties the routing cache if enabled.
*/
public void clearRoutingCache() {
if (DEBUG_CACHE) {
Log.d(TAG, "---- routing cache clear (from java) ----------");
}
invalidateRoutingCache();
}
/**
* @see AudioManager#addOnDevicesForAttributesChangedListener(
* AudioAttributes, Executor, OnDevicesForAttributesChangedListener)
@@ -464,6 +474,7 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback,
* @return
*/
public int setParameters(String keyValuePairs) {
invalidateRoutingCache();
return AudioSystem.setParameters(keyValuePairs);
}

View File

@@ -74,7 +74,7 @@ public class AudioDeviceBrokerTest {
mSpyDevInventory = spy(new AudioDeviceInventory(mSpyAudioSystem));
mSpySystemServer = spy(new NoOpSystemServerAdapter());
mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory,
mSpySystemServer);
mSpySystemServer, mSpyAudioSystem);
mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker);
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();