summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vlad Popa <pvlad@google.com> 2025-01-17 17:58:14 -0800
committer Vlad Popa <pvlad@google.com> 2025-01-24 10:30:21 -0800
commit4f416c50a7cb590336be31180bf8e3deee2afb4e (patch)
tree75f4b3b7fbbb0cce424f7e2ab08c01e76cf24b28
parent515b50095b02ca1dcc652ae4f120bf116278050c (diff)
Use cache for volume getter
Using the IpcDataCache to reduce the number of binder calls between AudioManager and AudioService. From the b/383667500 we see that there are a lot of calls that can be optimized. We need to investigate whether the IpcDataCache mechanism is more efficient in this case since the volumes might get invalidated very often depending on the routing and mute state. Flag: android.media.audio.cache_get_stream_volume Test: atest AudioManagerTest Bug: 383667500 Change-Id: I8a07d0f728149e2a9bfcaeee81fff60b17ceedb5
-rw-r--r--media/java/android/media/AudioManager.java32
-rw-r--r--media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java36
-rw-r--r--services/core/java/com/android/server/audio/AudioManagerShellCommand.java13
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java41
4 files changed, 103 insertions, 19 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index aa3dbda374be..71013f7f4e34 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -22,6 +22,7 @@ import static android.content.Context.DEVICE_ID_DEFAULT;
import static android.media.audio.Flags.autoPublicVolumeApiHardening;
import static android.media.audio.Flags.automaticBtDeviceType;
import static android.media.audio.Flags.cacheGetStreamMinMaxVolume;
+import static android.media.audio.Flags.cacheGetStreamVolume;
import static android.media.audio.Flags.FLAG_DEPRECATE_STREAM_BT_SCO;
import static android.media.audio.Flags.FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING;
import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API;
@@ -1241,7 +1242,12 @@ public class AudioManager {
* @hide
**/
public static final String VOLUME_MAX_CACHING_API = "getStreamMaxVolume";
- private static final int VOLUME_MIN_MAX_CACHING_SIZE = 16;
+ /**
+ * API string for caching the volume for each stream
+ * @hide
+ **/
+ public static final String VOLUME_CACHING_API = "getStreamVolume";
+ private static final int VOLUME_CACHING_SIZE = 16;
private final IpcDataCache.QueryHandler<VolumeCacheQuery, Integer> mVolQuery =
new IpcDataCache.QueryHandler<>() {
@@ -1252,6 +1258,7 @@ public class AudioManager {
return switch (query.queryCommand) {
case QUERY_VOL_MIN -> service.getStreamMinVolume(query.stream);
case QUERY_VOL_MAX -> service.getStreamMaxVolume(query.stream);
+ case QUERY_VOL -> service.getStreamVolume(query.stream);
default -> {
Log.w(TAG, "Not a valid volume cache query: " + query);
yield null;
@@ -1265,29 +1272,40 @@ public class AudioManager {
};
private final IpcDataCache<VolumeCacheQuery, Integer> mVolMinCache =
- new IpcDataCache<>(VOLUME_MIN_MAX_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM,
+ new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM,
VOLUME_MIN_CACHING_API, VOLUME_MIN_CACHING_API, mVolQuery);
private final IpcDataCache<VolumeCacheQuery, Integer> mVolMaxCache =
- new IpcDataCache<>(VOLUME_MIN_MAX_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM,
+ new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM,
VOLUME_MAX_CACHING_API, VOLUME_MAX_CACHING_API, mVolQuery);
+ private final IpcDataCache<VolumeCacheQuery, Integer> mVolCache =
+ new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM,
+ VOLUME_CACHING_API, VOLUME_CACHING_API, mVolQuery);
+
/**
* Used to invalidate the cache for the given API
* @hide
**/
public static void clearVolumeCache(String api) {
- if (cacheGetStreamMinMaxVolume()) {
+ if (cacheGetStreamMinMaxVolume() && (VOLUME_MAX_CACHING_API.equals(api)
+ || VOLUME_MIN_CACHING_API.equals(api))) {
+ IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, api);
+ } else if (cacheGetStreamVolume() && VOLUME_CACHING_API.equals(api)) {
IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, api);
+ } else {
+ Log.w(TAG, "invalid clearVolumeCache for api " + api);
}
}
private static final int QUERY_VOL_MIN = 1;
private static final int QUERY_VOL_MAX = 2;
+ private static final int QUERY_VOL = 3;
/** @hide */
@IntDef(prefix = "QUERY_VOL", value = {
QUERY_VOL_MIN,
- QUERY_VOL_MAX}
+ QUERY_VOL_MAX,
+ QUERY_VOL}
)
@Retention(RetentionPolicy.SOURCE)
private @interface QueryVolCommand {}
@@ -1297,6 +1315,7 @@ public class AudioManager {
return switch (queryCommand) {
case QUERY_VOL_MIN -> "getStreamMinVolume";
case QUERY_VOL_MAX -> "getStreamMaxVolume";
+ case QUERY_VOL -> "getStreamVolume";
default -> "invalid command";
};
}
@@ -1373,6 +1392,9 @@ public class AudioManager {
* @see #setStreamVolume(int, int, int)
*/
public int getStreamVolume(int streamType) {
+ if (cacheGetStreamVolume()) {
+ return mVolCache.query(new VolumeCacheQuery(streamType, QUERY_VOL));
+ }
final IAudioService service = getService();
try {
return service.getStreamVolume(streamType);
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java
index 017a1029d35c..209734ca4a53 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java
@@ -67,6 +67,17 @@ public class AudioManagerTest {
private AudioManager mAudioManager;
+ private static final int[] PUBLIC_STREAM_TYPES = {
+ STREAM_VOICE_CALL,
+ STREAM_SYSTEM,
+ STREAM_RING,
+ STREAM_MUSIC,
+ STREAM_ALARM,
+ STREAM_NOTIFICATION,
+ STREAM_DTMF,
+ STREAM_ACCESSIBILITY,
+ };
+
@Rule
public final AudioVolumesTestRule rule = new AudioVolumesTestRule();
@@ -226,18 +237,8 @@ public class AudioManagerTest {
public void getStreamMinMaxVolume_consistentWithAs() throws Exception {
IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
IAudioService service = IAudioService.Stub.asInterface(b);
- final int[] streamTypes = {
- STREAM_VOICE_CALL,
- STREAM_SYSTEM,
- STREAM_RING,
- STREAM_MUSIC,
- STREAM_ALARM,
- STREAM_NOTIFICATION,
- STREAM_DTMF,
- STREAM_ACCESSIBILITY,
- };
-
- for (int streamType : streamTypes) {
+
+ for (int streamType : PUBLIC_STREAM_TYPES) {
assertEquals(service.getStreamMinVolume(streamType),
mAudioManager.getStreamMinVolume(streamType));
assertEquals(service.getStreamMaxVolume(streamType),
@@ -245,6 +246,17 @@ public class AudioManagerTest {
}
}
+ @Test
+ public void getStreamVolume_consistentWithAs() throws Exception {
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ IAudioService service = IAudioService.Stub.asInterface(b);
+
+ for (int streamType : PUBLIC_STREAM_TYPES) {
+ assertEquals(service.getStreamVolume(streamType),
+ mAudioManager.getStreamVolume(streamType));
+ }
+ }
+
//-----------------------------------------------------------------
// Test Volume per Attributes setter/getters
//-----------------------------------------------------------------
diff --git a/services/core/java/com/android/server/audio/AudioManagerShellCommand.java b/services/core/java/com/android/server/audio/AudioManagerShellCommand.java
index c35f4fca6edd..fece7a899f0a 100644
--- a/services/core/java/com/android/server/audio/AudioManagerShellCommand.java
+++ b/services/core/java/com/android/server/audio/AudioManagerShellCommand.java
@@ -69,6 +69,8 @@ class AudioManagerShellCommand extends ShellCommand {
return getMinVolume();
case "get-max-volume":
return getMaxVolume();
+ case "get-stream-volume":
+ return getStreamVolume();
case "set-device-volume":
return setDeviceVolume();
case "adj-mute":
@@ -114,6 +116,8 @@ class AudioManagerShellCommand extends ShellCommand {
pw.println(" Gets the min volume for STREAM_TYPE");
pw.println(" get-max-volume STREAM_TYPE");
pw.println(" Gets the max volume for STREAM_TYPE");
+ pw.println(" get-stream-volume STREAM_TYPE");
+ pw.println(" Gets the volume for STREAM_TYPE");
pw.println(" set-device-volume STREAM_TYPE VOLUME_INDEX NATIVE_DEVICE_TYPE");
pw.println(" Sets for NATIVE_DEVICE_TYPE the STREAM_TYPE volume to VOLUME_INDEX");
pw.println(" adj-mute STREAM_TYPE");
@@ -322,6 +326,15 @@ class AudioManagerShellCommand extends ShellCommand {
return 0;
}
+ private int getStreamVolume() {
+ final Context context = mService.mContext;
+ final AudioManager am = context.getSystemService(AudioManager.class);
+ final int stream = readIntArg();
+ final int result = am.getStreamVolume(stream);
+ getOutPrintWriter().println("AudioManager.getStreamVolume(" + stream + ") -> " + result);
+ return 0;
+ }
+
private int setDeviceVolume() {
final Context context = mService.mContext;
final AudioDeviceVolumeManager advm = (AudioDeviceVolumeManager) context.getSystemService(
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1baded86705e..ddce8c7051ea 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -50,6 +50,7 @@ import static android.media.AudioManager.STREAM_SYSTEM;
import static android.media.audio.Flags.autoPublicVolumeApiHardening;
import static android.media.audio.Flags.automaticBtDeviceType;
import static android.media.audio.Flags.cacheGetStreamMinMaxVolume;
+import static android.media.audio.Flags.cacheGetStreamVolume;
import static android.media.audio.Flags.concurrentAudioRecordBypassPermission;
import static android.media.audio.Flags.featureSpatialAudioHeadtrackingLowLatency;
import static android.media.audio.Flags.focusFreezeTestApi;
@@ -1890,6 +1891,12 @@ public class AudioService extends IAudioService.Stub
mSpatializerHelper.onRoutingUpdated();
}
checkMuteAwaitConnection();
+ if (cacheGetStreamVolume()) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "Clear volume cache after routing update");
+ }
+ AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API);
+ }
}
//-----------------------------------------------------------------
@@ -4968,6 +4975,8 @@ public class AudioService extends IAudioService.Stub
+ concurrentAudioRecordBypassPermission());
pw.println("\tandroid.media.audio.Flags.cacheGetStreamMinMaxVolume:"
+ cacheGetStreamMinMaxVolume());
+ pw.println("\tandroid.media.audio.Flags.cacheGetStreamVolume:"
+ + cacheGetStreamVolume());
}
private void dumpAudioMode(PrintWriter pw) {
@@ -7034,6 +7043,13 @@ public class AudioService extends IAudioService.Stub
streamState.mIsMuted = false;
}
}
+ if (cacheGetStreamVolume()) {
+ if (DEBUG_VOL) {
+ Log.d(TAG,
+ "Clear volume cache after possibly changing mute in readAudioSettings");
+ }
+ AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API);
+ }
}
readVolumeGroupsSettings(userSwitch);
@@ -9254,11 +9270,23 @@ public class AudioService extends IAudioService.Stub
public void put(int key, int value) {
super.put(key, value);
record("put", key, value);
+ if (cacheGetStreamVolume()) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "Clear volume cache after update index map");
+ }
+ AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API);
+ }
}
@Override
public void setValueAt(int index, int value) {
super.setValueAt(index, value);
record("setValueAt", keyAt(index), value);
+ if (cacheGetStreamVolume()) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "Clear volume cache after update index map");
+ }
+ AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API);
+ }
}
// Record all changes in the VolumeStreamState
@@ -9988,8 +10016,9 @@ public class AudioService extends IAudioService.Stub
* @return true if the mute state was changed
*/
public boolean mute(boolean state, boolean apply, String src) {
+ boolean changed;
synchronized (VolumeStreamState.class) {
- boolean changed = state != mIsMuted;
+ changed = state != mIsMuted;
if (changed) {
sMuteLogger.enqueue(
new AudioServiceEvents.StreamMuteEvent(mStreamType, state, src));
@@ -10007,8 +10036,16 @@ public class AudioService extends IAudioService.Stub
doMute();
}
}
- return changed;
}
+
+ if (cacheGetStreamVolume() && changed) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "Clear volume cache after changing mute state");
+ }
+ AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API);
+ }
+
+ return changed;
}
public void doMute() {