summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2020-12-23 19:57:11 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-12-23 19:57:11 +0000
commit4fa37e6985474cedeba3832f75bc1b4e3a10c522 (patch)
treeb4fb8d28346e27daa06af7d22c300f0680396feb
parent2d6a37ea0e42042cc6c125c97ec11a6c2584cec6 (diff)
parent1db3a365dcab098acc62a392d0849b90ccd15ca9 (diff)
Merge "AudioService: cache routing queries by stream types"
-rw-r--r--core/jni/android_media_AudioSystem.cpp27
-rw-r--r--media/java/android/media/AudioSystem.java40
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioSystemAdapter.java161
4 files changed, 228 insertions, 4 deletions
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 5cffbefbd9a3..2871aa1ffeba 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -171,6 +171,7 @@ static struct {
static struct {
jmethodID postDynPolicyEventFromNative;
jmethodID postRecordConfigEventFromNative;
+ jmethodID postRoutingUpdatedFromNative;
} gAudioPolicyEventHandlerMethods;
static struct { jmethodID add; } gListMethods;
@@ -539,6 +540,21 @@ android_media_AudioSystem_recording_callback(int event,
env->DeleteLocalRef(jEffects);
}
+static void
+android_media_AudioSystem_routing_callback()
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ // callback into java
+ jclass clazz = env->FindClass(kClassPathName);
+
+ if (env == NULL) {
+ return;
+ }
+ env->CallStaticVoidMethod(clazz,
+ gAudioPolicyEventHandlerMethods.postRoutingUpdatedFromNative);
+ env->DeleteLocalRef(clazz);
+}
+
static jint
android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name,
jint codec)
@@ -1894,6 +1910,12 @@ android_media_AudioSystem_registerRecordingCallback(JNIEnv *env, jobject thiz)
AudioSystem::setRecordConfigCallback(android_media_AudioSystem_recording_callback);
}
+static void
+android_media_AudioSystem_registerRoutingCallback(JNIEnv *env, jobject thiz)
+{
+ AudioSystem::setRoutingCallback(android_media_AudioSystem_routing_callback);
+}
+
static jint convertAudioMixToNative(JNIEnv *env,
AudioMix *nAudioMix,
@@ -2579,6 +2601,8 @@ static const JNINativeMethod gMethods[] =
(void *)android_media_AudioSystem_registerDynPolicyCallback},
{"native_register_recording_callback", "()V",
(void *)android_media_AudioSystem_registerRecordingCallback},
+ {"native_register_routing_callback", "()V",
+ (void *)android_media_AudioSystem_registerRoutingCallback},
{"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
{"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB},
{"native_get_offload_support", "(IIIII)I",
@@ -2762,6 +2786,9 @@ int register_android_media_AudioSystem(JNIEnv *env)
gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative =
GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
"recordingCallbackFromNative", "(IIIIIIZ[I[Landroid/media/audiofx/AudioEffect$Descriptor;[Landroid/media/audiofx/AudioEffect$Descriptor;I)V");
+ gAudioPolicyEventHandlerMethods.postRoutingUpdatedFromNative =
+ GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
+ "routingCallbackFromNative", "()V");
jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 164b194996a6..81ef06400521 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -31,6 +31,8 @@ import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Pair;
+import com.android.internal.annotations.GuardedBy;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -712,6 +714,42 @@ public class AudioSystem
}
}
+ /**
+ * @hide
+ * Handles events from the audio policy manager about routing events
+ */
+ public interface RoutingUpdateCallback {
+ /**
+ * Callback to notify a routing update event occurred
+ */
+ void onRoutingUpdated();
+ }
+
+ @GuardedBy("AudioSystem.class")
+ private static RoutingUpdateCallback sRoutingUpdateCallback;
+
+ /** @hide */
+ public static void setRoutingCallback(RoutingUpdateCallback cb) {
+ synchronized (AudioSystem.class) {
+ sRoutingUpdateCallback = cb;
+ native_register_routing_callback();
+ }
+ }
+
+ private static void routingCallbackFromNative() {
+ final RoutingUpdateCallback cb;
+ synchronized (AudioSystem.class) {
+ cb = sRoutingUpdateCallback;
+ }
+ //###
+ Log.i(TAG, "#################### update");
+ if (cb == null) {
+ Log.e(TAG, "routing update from APM was not captured");
+ return;
+ }
+ cb.onRoutingUpdated();
+ }
+
/*
* Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...)
* Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h
@@ -1597,6 +1635,8 @@ public class AudioSystem
private static native final void native_register_dynamic_policy_callback();
// declare this instance as having a recording configuration update callback handler
private static native final void native_register_recording_callback();
+ // declare this instance as having a routing update callback handler
+ private static native void native_register_routing_callback();
// must be kept in sync with value in include/system/audio.h
/** @hide */ public static final int AUDIO_HW_SYNC_INVALID = 0;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ada67b1d59af..2ab5aa616748 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3467,6 +3467,8 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#getStreamVolume(int) */
public int getStreamVolume(int streamType) {
ensureValidStreamType(streamType);
+ Log.e(TAG, "AudioSystem.getDevicesForStream In AudioService from u/pid"
+ + Binder.getCallingUid() + "/" + Binder.getCallingPid());
int device = getDeviceForStream(streamType);
synchronized (VolumeStreamState.class) {
int index = mStreamStates[streamType].getIndex(device);
@@ -7951,6 +7953,8 @@ public class AudioService extends IAudioService.Stub
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ mAudioSystem.dump(pw);
+
sLifecycleLogger.dump(pw);
if (mAudioHandler != null) {
pw.println("\nMessage handler (watch for unhandled messages):");
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 891c713d30fb..ff84505e59a9 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -21,9 +21,13 @@ import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
import android.media.AudioSystem;
import android.media.audiopolicy.AudioMix;
+import android.os.SystemClock;
+import android.util.Log;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Provides an adapter to access functionality of the android.media.AudioSystem class for device
@@ -31,15 +35,79 @@ import java.util.List;
* Use the "real" AudioSystem through the default adapter.
* Use the "always ok" adapter to avoid dealing with the APM behaviors during a test.
*/
-public class AudioSystemAdapter {
+public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback {
+
+ private static final String TAG = "AudioSystemAdapter";
+
+ // initialized in factory getDefaultAdapter()
+ private static AudioSystemAdapter sSingletonDefaultAdapter;
+
+ /**
+ * should be false by default unless enabling measurements of method call counts and time spent
+ * in measured methods
+ */
+ private static final boolean ENABLE_GETDEVICES_STATS = false;
+ private static final int NB_MEASUREMENTS = 2;
+ private static final int METHOD_GETDEVICESFORSTREAM = 0;
+ private static final int METHOD_GETDEVICESFORATTRIBUTES = 1;
+ private long[] mMethodTimeNs;
+ private int[] mMethodCallCounter;
+ private String[] mMethodNames = {"getDevicesForStream", "getDevicesForAttributes"};
+
+ private static final boolean USE_CACHE_FOR_GETDEVICES = true;
+ private ConcurrentHashMap<Integer, Integer> mDevicesForStreamCache;
+ private int[] mMethodCacheHit;
+
+ /**
+ * should be false except when trying to debug caching errors. When true, the value retrieved
+ * from the cache will be compared against the real queried value, which defeats the purpose of
+ * the cache in terms of performance.
+ */
+ private static final boolean DEBUG_CACHE = false;
+
+ /**
+ * Implementation of AudioSystem.RoutingUpdateCallback
+ */
+ @Override
+ public void onRoutingUpdated() {
+ if (DEBUG_CACHE) {
+ Log.d(TAG, "---- onRoutingUpdated (from native) ----------");
+ }
+ invalidateRoutingCache();
+ }
/**
* Create a wrapper around the {@link AudioSystem} static methods, all functions are directly
* forwarded to the AudioSystem class.
* @return an adapter around AudioSystem
*/
- static final @NonNull AudioSystemAdapter getDefaultAdapter() {
- return new AudioSystemAdapter();
+ static final synchronized @NonNull AudioSystemAdapter getDefaultAdapter() {
+ if (sSingletonDefaultAdapter == null) {
+ sSingletonDefaultAdapter = new AudioSystemAdapter();
+ AudioSystem.setRoutingCallback(sSingletonDefaultAdapter);
+ if (USE_CACHE_FOR_GETDEVICES) {
+ sSingletonDefaultAdapter.mDevicesForStreamCache =
+ new ConcurrentHashMap<Integer, Integer>(AudioSystem.getNumStreamTypes());
+ sSingletonDefaultAdapter.mMethodCacheHit = new int[NB_MEASUREMENTS];
+ }
+ if (ENABLE_GETDEVICES_STATS) {
+ sSingletonDefaultAdapter.mMethodCallCounter = new int[NB_MEASUREMENTS];
+ sSingletonDefaultAdapter.mMethodTimeNs = new long[NB_MEASUREMENTS];
+ }
+ }
+ return sSingletonDefaultAdapter;
+ }
+
+ private void invalidateRoutingCache() {
+ if (DEBUG_CACHE) {
+ Log.d(TAG, "---- clearing cache ----------");
+ }
+ if (mDevicesForStreamCache == null) {
+ return;
+ }
+ synchronized (mDevicesForStreamCache) {
+ mDevicesForStreamCache.clear();
+ }
}
/**
@@ -48,6 +116,44 @@ public class AudioSystemAdapter {
* @return a mask of device types
*/
public int getDevicesForStream(int stream) {
+ if (!ENABLE_GETDEVICES_STATS) {
+ return getDevicesForStreamImpl(stream);
+ }
+ mMethodCallCounter[METHOD_GETDEVICESFORSTREAM]++;
+ final long startTime = SystemClock.uptimeNanos();
+ final int res = getDevicesForStreamImpl(stream);
+ mMethodTimeNs[METHOD_GETDEVICESFORSTREAM] += SystemClock.uptimeNanos() - startTime;
+ return res;
+ }
+
+ private int getDevicesForStreamImpl(int stream) {
+ if (USE_CACHE_FOR_GETDEVICES) {
+ Integer res;
+ synchronized (mDevicesForStreamCache) {
+ res = mDevicesForStreamCache.get(stream);
+ if (res == null) {
+ res = AudioSystem.getDevicesForStream(stream);
+ mDevicesForStreamCache.put(stream, res);
+ if (DEBUG_CACHE) {
+ Log.d(TAG, " stream=" + stream + " dev=0x" + Integer.toHexString(res));
+ }
+ return res;
+ }
+ // cache hit
+ mMethodCacheHit[METHOD_GETDEVICESFORSTREAM]++;
+ if (DEBUG_CACHE) {
+ final int real = AudioSystem.getDevicesForStream(stream);
+ if (res == real) {
+ Log.d(TAG, " stream=" + stream + " dev=0x" + Integer.toHexString(res)
+ + " CACHE");
+ } else {
+ Log.e(TAG, " stream=" + stream + " dev=0x" + Integer.toHexString(res)
+ + " CACHE ERROR real dev=0x" + Integer.toHexString(real));
+ }
+ }
+ }
+ return res;
+ }
return AudioSystem.getDevicesForStream(stream);
}
@@ -58,6 +164,19 @@ public class AudioSystemAdapter {
*/
public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
@NonNull AudioAttributes attributes) {
+ if (!ENABLE_GETDEVICES_STATS) {
+ return getDevicesForAttributesImpl(attributes);
+ }
+ mMethodCallCounter[METHOD_GETDEVICESFORATTRIBUTES]++;
+ final long startTime = SystemClock.uptimeNanos();
+ final ArrayList<AudioDeviceAttributes> res = getDevicesForAttributesImpl(attributes);
+ mMethodTimeNs[METHOD_GETDEVICESFORATTRIBUTES] += SystemClock.uptimeNanos() - startTime;
+ return res;
+ }
+
+ private @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesImpl(
+ @NonNull AudioAttributes attributes) {
+ // TODO implement caching for attributes-based routing
return AudioSystem.getDevicesForAttributes(attributes);
}
@@ -72,6 +191,7 @@ public class AudioSystemAdapter {
*/
public int setDeviceConnectionState(int device, int state, String deviceAddress,
String deviceName, int codecFormat) {
+ invalidateRoutingCache();
return AudioSystem.setDeviceConnectionState(device, state, deviceAddress, deviceName,
codecFormat);
}
@@ -96,6 +216,7 @@ public class AudioSystemAdapter {
*/
public int handleDeviceConfigChange(int device, String deviceAddress,
String deviceName, int codecFormat) {
+ invalidateRoutingCache();
return AudioSystem.handleDeviceConfigChange(device, deviceAddress, deviceName,
codecFormat);
}
@@ -109,6 +230,7 @@ public class AudioSystemAdapter {
*/
public int setDevicesRoleForStrategy(int strategy, int role,
@NonNull List<AudioDeviceAttributes> devices) {
+ invalidateRoutingCache();
return AudioSystem.setDevicesRoleForStrategy(strategy, role, devices);
}
@@ -119,6 +241,7 @@ public class AudioSystemAdapter {
* @return
*/
public int removeDevicesRoleForStrategy(int strategy, int role) {
+ invalidateRoutingCache();
return AudioSystem.removeDevicesRoleForStrategy(strategy, role);
}
@@ -131,11 +254,12 @@ public class AudioSystemAdapter {
*/
public int setDevicesRoleForCapturePreset(int capturePreset, int role,
@NonNull List<AudioDeviceAttributes> devices) {
+ invalidateRoutingCache();
return AudioSystem.setDevicesRoleForCapturePreset(capturePreset, role, devices);
}
/**
- * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int)}
+ * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int, int[], String[])}
* @param capturePreset
* @param role
* @param devicesToRemove
@@ -143,6 +267,7 @@ public class AudioSystemAdapter {
*/
public int removeDevicesRoleForCapturePreset(
int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove) {
+ invalidateRoutingCache();
return AudioSystem.removeDevicesRoleForCapturePreset(capturePreset, role, devicesToRemove);
}
@@ -153,6 +278,7 @@ public class AudioSystemAdapter {
* @return
*/
public int clearDevicesRoleForCapturePreset(int capturePreset, int role) {
+ invalidateRoutingCache();
return AudioSystem.clearDevicesRoleForCapturePreset(capturePreset, role);
}
@@ -218,6 +344,7 @@ public class AudioSystemAdapter {
* @return
*/
public int setPhoneState(int state, int uid) {
+ invalidateRoutingCache();
return AudioSystem.setPhoneState(state, uid);
}
@@ -238,6 +365,7 @@ public class AudioSystemAdapter {
* @return
*/
public int setForceUse(int usage, int config) {
+ invalidateRoutingCache();
return AudioSystem.setForceUse(usage, config);
}
@@ -257,6 +385,7 @@ public class AudioSystemAdapter {
* @return
*/
public int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register) {
+ invalidateRoutingCache();
return AudioSystem.registerPolicyMixes(mixes, register);
}
@@ -268,6 +397,7 @@ public class AudioSystemAdapter {
* @return
*/
public int setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+ invalidateRoutingCache();
return AudioSystem.setUidDeviceAffinities(uid, types, addresses);
}
@@ -277,6 +407,7 @@ public class AudioSystemAdapter {
* @return
*/
public int removeUidDeviceAffinities(int uid) {
+ invalidateRoutingCache();
return AudioSystem.removeUidDeviceAffinities(uid);
}
@@ -289,6 +420,7 @@ public class AudioSystemAdapter {
*/
public int setUserIdDeviceAffinities(int userId, @NonNull int[] types,
@NonNull String[] addresses) {
+ invalidateRoutingCache();
return AudioSystem.setUserIdDeviceAffinities(userId, types, addresses);
}
@@ -298,6 +430,27 @@ public class AudioSystemAdapter {
* @return
*/
public int removeUserIdDeviceAffinities(int userId) {
+ invalidateRoutingCache();
return AudioSystem.removeUserIdDeviceAffinities(userId);
}
+
+ /**
+ * Part of AudioService dump
+ * @param pw
+ */
+ public void dump(PrintWriter pw) {
+ if (!ENABLE_GETDEVICES_STATS) {
+ // only stats in this dump
+ return;
+ }
+ pw.println("\nAudioSystemAdapter:");
+ for (int i = 0; i < NB_MEASUREMENTS; i++) {
+ pw.println(mMethodNames[i]
+ + ": counter=" + mMethodCallCounter[i]
+ + " time(ms)=" + (mMethodTimeNs[i] / 1E6)
+ + (USE_CACHE_FOR_GETDEVICES
+ ? (" FScacheHit=" + mMethodCacheHit[METHOD_GETDEVICESFORSTREAM]) : ""));
+ }
+ pw.println("\n");
+ }
}