Loading core/jni/android_media_AudioSystem.cpp +1 −71 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ #include <android_media_audiopolicy.h> #include <android_os_Parcel.h> #include <audiomanager/AudioManager.h> #include <android-base/properties.h> #include <binder/IBinder.h> #include <jni.h> #include <media/AidlConversion.h> Loading @@ -42,10 +41,8 @@ #include <system/audio_policy.h> #include <utils/Log.h> #include <thread> #include <optional> #include <sstream> #include <memory> #include <vector> #include "android_media_AudioAttributes.h" Loading Loading @@ -264,13 +261,6 @@ static struct { jfieldID mMixerBehavior; } gAudioMixerAttributesField; static struct { jclass clazz; jmethodID run; } gRunnableClassInfo; static JavaVM* gVm; static Mutex gLock; enum AudioError { Loading Loading @@ -3372,55 +3362,6 @@ static jboolean android_media_AudioSystem_isBluetoothVariableLatencyEnabled(JNIE return enabled; } class JavaSystemPropertyListener { public: JavaSystemPropertyListener(JNIEnv* env, jobject javaCallback, std::string sysPropName) : mCallback(env->NewGlobalRef(javaCallback)), mCachedProperty(android::base::CachedProperty{std::move(sysPropName)}) { mListenerThread = std::thread([this]() mutable { JNIEnv* threadEnv = GetOrAttachJNIEnvironment(gVm); while (!mCleanupSignal.load()) { using namespace std::chrono_literals; // 1s timeout so this thread can read the cleanup signal to (slowly) be able to // be destroyed. std::string newVal = mCachedProperty.WaitForChange(1000ms) ?: ""; if (newVal != "" && mLastVal != newVal) { threadEnv->CallVoidMethod(mCallback, gRunnableClassInfo.run); mLastVal = std::move(newVal); } } }); } ~JavaSystemPropertyListener() { mCleanupSignal.store(true); mListenerThread.join(); JNIEnv* env = GetOrAttachJNIEnvironment(gVm); env->DeleteGlobalRef(mCallback); } private: jobject mCallback; android::base::CachedProperty mCachedProperty; std::thread mListenerThread; std::atomic<bool> mCleanupSignal{false}; std::string mLastVal = ""; }; std::vector<std::unique_ptr<JavaSystemPropertyListener>> gSystemPropertyListeners; std::mutex gSysPropLock{}; static void android_media_AudioSystem_listenForSystemPropertyChange(JNIEnv *env, jobject thiz, jstring sysProp, jobject javaCallback) { ScopedUtfChars sysPropChars{env, sysProp}; auto listener = std::make_unique<JavaSystemPropertyListener>(env, javaCallback, std::string{sysPropChars.c_str()}); std::unique_lock _l{gSysPropLock}; gSystemPropertyListeners.push_back(std::move(listener)); } // ---------------------------------------------------------------------------- #define MAKE_AUDIO_SYSTEM_METHOD(x) \ Loading Loading @@ -3593,12 +3534,7 @@ static const JNINativeMethod gMethods[] = android_media_AudioSystem_clearPreferredMixerAttributes), MAKE_AUDIO_SYSTEM_METHOD(supportsBluetoothVariableLatency), MAKE_AUDIO_SYSTEM_METHOD(setBluetoothVariableLatencyEnabled), MAKE_AUDIO_SYSTEM_METHOD(isBluetoothVariableLatencyEnabled), MAKE_JNI_NATIVE_METHOD("listenForSystemPropertyChange", "(Ljava/lang/String;Ljava/lang/Runnable;)V", android_media_AudioSystem_listenForSystemPropertyChange), }; MAKE_AUDIO_SYSTEM_METHOD(isBluetoothVariableLatencyEnabled)}; static const JNINativeMethod gEventHandlerMethods[] = {MAKE_JNI_NATIVE_METHOD("native_setup", "(Ljava/lang/Object;)V", Loading Loading @@ -3880,12 +3816,6 @@ int register_android_media_AudioSystem(JNIEnv *env) gAudioMixerAttributesField.mMixerBehavior = GetFieldIDOrDie(env, audioMixerAttributesClass, "mMixerBehavior", "I"); jclass runnableClazz = FindClassOrDie(env, "java/lang/Runnable"); gRunnableClassInfo.clazz = MakeGlobalRefOrDie(env, runnableClazz); gRunnableClassInfo.run = GetMethodIDOrDie(env, runnableClazz, "run", "()V"); LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&gVm) != 0); AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback); RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); Loading media/java/android/media/AudioSystem.java +0 −7 Original line number Diff line number Diff line Loading @@ -2649,11 +2649,4 @@ public class AudioSystem * @hide */ public static native boolean isBluetoothVariableLatencyEnabled(); /** * Register a native listener for system property sysprop * @param callback the listener which fires when the property changes * @hide */ public static native void listenForSystemPropertyChange(String sysprop, Runnable callback); } services/core/java/com/android/server/audio/AudioService.java +25 −37 Original line number Diff line number Diff line Loading @@ -739,8 +739,6 @@ public class AudioService extends IAudioService.Stub // Broadcast receiver for device connections intent broadcasts private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); private final Executor mAudioServerLifecycleExecutor; private IMediaProjectionManager mProjectionService; // to validate projection token /** Interface for UserManagerService. */ Loading Loading @@ -1061,8 +1059,7 @@ public class AudioService extends IAudioService.Stub audioserverPermissions() ? initializeAudioServerPermissionProvider( context, audioPolicyFacade, audioserverLifecycleExecutor) : null, audioserverLifecycleExecutor null ); } Loading Loading @@ -1148,16 +1145,13 @@ public class AudioService extends IAudioService.Stub * {@link AudioSystemThread} is created as the messaging thread instead. * @param appOps {@link AppOpsManager} system service * @param enforcer Used for permission enforcing * @param permissionProvider Used to push permissions to audioserver * @param audioserverLifecycleExecutor Used for tasks managing audioserver lifecycle */ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer, SettingsAdapter settings, AudioVolumeGroupHelperBase audioVolumeGroupHelper, AudioPolicyFacade audioPolicy, @Nullable Looper looper, AppOpsManager appOps, @NonNull PermissionEnforcer enforcer, /* @NonNull */ AudioServerPermissionProvider permissionProvider, Executor audioserverLifecycleExecutor) { /* @NonNull */ AudioServerPermissionProvider permissionProvider) { super(enforcer); sLifecycleLogger.enqueue(new EventLogger.StringEvent("AudioService()")); mContext = context; Loading @@ -1165,7 +1159,6 @@ public class AudioService extends IAudioService.Stub mAppOps = appOps; mPermissionProvider = permissionProvider; mAudioServerLifecycleExecutor = audioserverLifecycleExecutor; mAudioSystem = audioSystem; mSystemServer = systemServer; Loading @@ -1177,34 +1170,6 @@ public class AudioService extends IAudioService.Stub mBroadcastHandlerThread = new HandlerThread("AudioService Broadcast"); mBroadcastHandlerThread.start(); // Listen to permission invalidations for the PermissionProvider if (audioserverPermissions()) { final Handler broadcastHandler = mBroadcastHandlerThread.getThreadHandler(); mAudioSystem.listenForSystemPropertyChange(PermissionManager.CACHE_KEY_PACKAGE_INFO, new Runnable() { // Roughly chosen to be long enough to suppress the autocork behavior // of the permission cache (50ms), and longer than the task could reasonably // take, even with many packages and users, while not introducing visible // permission leaks - since the app needs to restart, and trigger an action // which requires permissions from audioserver before this delay. // For RECORD_AUDIO, we are additionally protected by appops. final long UPDATE_DELAY_MS = 110; final AtomicLong scheduledUpdateTimestamp = new AtomicLong(0); @Override public void run() { var currentTime = SystemClock.uptimeMillis(); if (currentTime > scheduledUpdateTimestamp.get()) { scheduledUpdateTimestamp.set(currentTime + UPDATE_DELAY_MS); broadcastHandler.postAtTime( () -> mAudioServerLifecycleExecutor.execute(mPermissionProvider ::onPermissionStateChanged), currentTime + UPDATE_DELAY_MS ); } } }); } mDeviceBroker = new AudioDeviceBroker(mContext, this, mAudioSystem); mIsSingleVolume = AudioSystem.isSingleVolume(context); Loading Loading @@ -12000,6 +11965,29 @@ public class AudioService extends IAudioService.Stub provider.onServiceStart(audioPolicy.getPermissionController()); }); // Set up event listeners // Must be kept in sync with PermissionManager Runnable cacheSysPropHandler = new Runnable() { private AtomicReference<SystemProperties.Handle> mHandle = new AtomicReference(); private AtomicLong mNonce = new AtomicLong(); @Override public void run() { if (mHandle.get() == null) { // Cache the handle mHandle.compareAndSet(null, SystemProperties.find( PermissionManager.CACHE_KEY_PACKAGE_INFO)); } long nonce; SystemProperties.Handle ref; if ((ref = mHandle.get()) != null && (nonce = ref.getLong(0)) != 0 && mNonce.getAndSet(nonce) != nonce) { audioserverExecutor.execute(() -> provider.onPermissionStateChanged()); } } }; SystemProperties.addChangeCallback(cacheSysPropHandler); IntentFilter packageUpdateFilter = new IntentFilter(); packageUpdateFilter.addAction(ACTION_PACKAGE_ADDED); packageUpdateFilter.addAction(ACTION_PACKAGE_REMOVED); services/core/java/com/android/server/audio/AudioSystemAdapter.java +0 −4 Original line number Diff line number Diff line Loading @@ -748,10 +748,6 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback, return AudioSystem.setMasterMute(mute); } public void listenForSystemPropertyChange(String systemPropertyName, Runnable callback) { AudioSystem.listenForSystemPropertyChange(systemPropertyName, callback); } /** * Part of AudioService dump * @param pw Loading services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -101,7 +101,7 @@ public class AbsoluteVolumeBehaviorTest { mAudioService = new AudioService(mContext, mSpyAudioSystem, mSystemServer, mSettingsAdapter, mAudioVolumeGroupHelper, mMockAudioPolicy, mTestLooper.getLooper(), mock(AppOpsManager.class), mock(PermissionEnforcer.class), mock(AudioServerPermissionProvider.class), r -> r.run()) { mock(AudioServerPermissionProvider.class)) { @Override public int getDeviceForStream(int stream) { return AudioSystem.DEVICE_OUT_SPEAKER; Loading Loading
core/jni/android_media_AudioSystem.cpp +1 −71 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ #include <android_media_audiopolicy.h> #include <android_os_Parcel.h> #include <audiomanager/AudioManager.h> #include <android-base/properties.h> #include <binder/IBinder.h> #include <jni.h> #include <media/AidlConversion.h> Loading @@ -42,10 +41,8 @@ #include <system/audio_policy.h> #include <utils/Log.h> #include <thread> #include <optional> #include <sstream> #include <memory> #include <vector> #include "android_media_AudioAttributes.h" Loading Loading @@ -264,13 +261,6 @@ static struct { jfieldID mMixerBehavior; } gAudioMixerAttributesField; static struct { jclass clazz; jmethodID run; } gRunnableClassInfo; static JavaVM* gVm; static Mutex gLock; enum AudioError { Loading Loading @@ -3372,55 +3362,6 @@ static jboolean android_media_AudioSystem_isBluetoothVariableLatencyEnabled(JNIE return enabled; } class JavaSystemPropertyListener { public: JavaSystemPropertyListener(JNIEnv* env, jobject javaCallback, std::string sysPropName) : mCallback(env->NewGlobalRef(javaCallback)), mCachedProperty(android::base::CachedProperty{std::move(sysPropName)}) { mListenerThread = std::thread([this]() mutable { JNIEnv* threadEnv = GetOrAttachJNIEnvironment(gVm); while (!mCleanupSignal.load()) { using namespace std::chrono_literals; // 1s timeout so this thread can read the cleanup signal to (slowly) be able to // be destroyed. std::string newVal = mCachedProperty.WaitForChange(1000ms) ?: ""; if (newVal != "" && mLastVal != newVal) { threadEnv->CallVoidMethod(mCallback, gRunnableClassInfo.run); mLastVal = std::move(newVal); } } }); } ~JavaSystemPropertyListener() { mCleanupSignal.store(true); mListenerThread.join(); JNIEnv* env = GetOrAttachJNIEnvironment(gVm); env->DeleteGlobalRef(mCallback); } private: jobject mCallback; android::base::CachedProperty mCachedProperty; std::thread mListenerThread; std::atomic<bool> mCleanupSignal{false}; std::string mLastVal = ""; }; std::vector<std::unique_ptr<JavaSystemPropertyListener>> gSystemPropertyListeners; std::mutex gSysPropLock{}; static void android_media_AudioSystem_listenForSystemPropertyChange(JNIEnv *env, jobject thiz, jstring sysProp, jobject javaCallback) { ScopedUtfChars sysPropChars{env, sysProp}; auto listener = std::make_unique<JavaSystemPropertyListener>(env, javaCallback, std::string{sysPropChars.c_str()}); std::unique_lock _l{gSysPropLock}; gSystemPropertyListeners.push_back(std::move(listener)); } // ---------------------------------------------------------------------------- #define MAKE_AUDIO_SYSTEM_METHOD(x) \ Loading Loading @@ -3593,12 +3534,7 @@ static const JNINativeMethod gMethods[] = android_media_AudioSystem_clearPreferredMixerAttributes), MAKE_AUDIO_SYSTEM_METHOD(supportsBluetoothVariableLatency), MAKE_AUDIO_SYSTEM_METHOD(setBluetoothVariableLatencyEnabled), MAKE_AUDIO_SYSTEM_METHOD(isBluetoothVariableLatencyEnabled), MAKE_JNI_NATIVE_METHOD("listenForSystemPropertyChange", "(Ljava/lang/String;Ljava/lang/Runnable;)V", android_media_AudioSystem_listenForSystemPropertyChange), }; MAKE_AUDIO_SYSTEM_METHOD(isBluetoothVariableLatencyEnabled)}; static const JNINativeMethod gEventHandlerMethods[] = {MAKE_JNI_NATIVE_METHOD("native_setup", "(Ljava/lang/Object;)V", Loading Loading @@ -3880,12 +3816,6 @@ int register_android_media_AudioSystem(JNIEnv *env) gAudioMixerAttributesField.mMixerBehavior = GetFieldIDOrDie(env, audioMixerAttributesClass, "mMixerBehavior", "I"); jclass runnableClazz = FindClassOrDie(env, "java/lang/Runnable"); gRunnableClassInfo.clazz = MakeGlobalRefOrDie(env, runnableClazz); gRunnableClassInfo.run = GetMethodIDOrDie(env, runnableClazz, "run", "()V"); LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&gVm) != 0); AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback); RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); Loading
media/java/android/media/AudioSystem.java +0 −7 Original line number Diff line number Diff line Loading @@ -2649,11 +2649,4 @@ public class AudioSystem * @hide */ public static native boolean isBluetoothVariableLatencyEnabled(); /** * Register a native listener for system property sysprop * @param callback the listener which fires when the property changes * @hide */ public static native void listenForSystemPropertyChange(String sysprop, Runnable callback); }
services/core/java/com/android/server/audio/AudioService.java +25 −37 Original line number Diff line number Diff line Loading @@ -739,8 +739,6 @@ public class AudioService extends IAudioService.Stub // Broadcast receiver for device connections intent broadcasts private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); private final Executor mAudioServerLifecycleExecutor; private IMediaProjectionManager mProjectionService; // to validate projection token /** Interface for UserManagerService. */ Loading Loading @@ -1061,8 +1059,7 @@ public class AudioService extends IAudioService.Stub audioserverPermissions() ? initializeAudioServerPermissionProvider( context, audioPolicyFacade, audioserverLifecycleExecutor) : null, audioserverLifecycleExecutor null ); } Loading Loading @@ -1148,16 +1145,13 @@ public class AudioService extends IAudioService.Stub * {@link AudioSystemThread} is created as the messaging thread instead. * @param appOps {@link AppOpsManager} system service * @param enforcer Used for permission enforcing * @param permissionProvider Used to push permissions to audioserver * @param audioserverLifecycleExecutor Used for tasks managing audioserver lifecycle */ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer, SettingsAdapter settings, AudioVolumeGroupHelperBase audioVolumeGroupHelper, AudioPolicyFacade audioPolicy, @Nullable Looper looper, AppOpsManager appOps, @NonNull PermissionEnforcer enforcer, /* @NonNull */ AudioServerPermissionProvider permissionProvider, Executor audioserverLifecycleExecutor) { /* @NonNull */ AudioServerPermissionProvider permissionProvider) { super(enforcer); sLifecycleLogger.enqueue(new EventLogger.StringEvent("AudioService()")); mContext = context; Loading @@ -1165,7 +1159,6 @@ public class AudioService extends IAudioService.Stub mAppOps = appOps; mPermissionProvider = permissionProvider; mAudioServerLifecycleExecutor = audioserverLifecycleExecutor; mAudioSystem = audioSystem; mSystemServer = systemServer; Loading @@ -1177,34 +1170,6 @@ public class AudioService extends IAudioService.Stub mBroadcastHandlerThread = new HandlerThread("AudioService Broadcast"); mBroadcastHandlerThread.start(); // Listen to permission invalidations for the PermissionProvider if (audioserverPermissions()) { final Handler broadcastHandler = mBroadcastHandlerThread.getThreadHandler(); mAudioSystem.listenForSystemPropertyChange(PermissionManager.CACHE_KEY_PACKAGE_INFO, new Runnable() { // Roughly chosen to be long enough to suppress the autocork behavior // of the permission cache (50ms), and longer than the task could reasonably // take, even with many packages and users, while not introducing visible // permission leaks - since the app needs to restart, and trigger an action // which requires permissions from audioserver before this delay. // For RECORD_AUDIO, we are additionally protected by appops. final long UPDATE_DELAY_MS = 110; final AtomicLong scheduledUpdateTimestamp = new AtomicLong(0); @Override public void run() { var currentTime = SystemClock.uptimeMillis(); if (currentTime > scheduledUpdateTimestamp.get()) { scheduledUpdateTimestamp.set(currentTime + UPDATE_DELAY_MS); broadcastHandler.postAtTime( () -> mAudioServerLifecycleExecutor.execute(mPermissionProvider ::onPermissionStateChanged), currentTime + UPDATE_DELAY_MS ); } } }); } mDeviceBroker = new AudioDeviceBroker(mContext, this, mAudioSystem); mIsSingleVolume = AudioSystem.isSingleVolume(context); Loading Loading @@ -12000,6 +11965,29 @@ public class AudioService extends IAudioService.Stub provider.onServiceStart(audioPolicy.getPermissionController()); }); // Set up event listeners // Must be kept in sync with PermissionManager Runnable cacheSysPropHandler = new Runnable() { private AtomicReference<SystemProperties.Handle> mHandle = new AtomicReference(); private AtomicLong mNonce = new AtomicLong(); @Override public void run() { if (mHandle.get() == null) { // Cache the handle mHandle.compareAndSet(null, SystemProperties.find( PermissionManager.CACHE_KEY_PACKAGE_INFO)); } long nonce; SystemProperties.Handle ref; if ((ref = mHandle.get()) != null && (nonce = ref.getLong(0)) != 0 && mNonce.getAndSet(nonce) != nonce) { audioserverExecutor.execute(() -> provider.onPermissionStateChanged()); } } }; SystemProperties.addChangeCallback(cacheSysPropHandler); IntentFilter packageUpdateFilter = new IntentFilter(); packageUpdateFilter.addAction(ACTION_PACKAGE_ADDED); packageUpdateFilter.addAction(ACTION_PACKAGE_REMOVED);
services/core/java/com/android/server/audio/AudioSystemAdapter.java +0 −4 Original line number Diff line number Diff line Loading @@ -748,10 +748,6 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback, return AudioSystem.setMasterMute(mute); } public void listenForSystemPropertyChange(String systemPropertyName, Runnable callback) { AudioSystem.listenForSystemPropertyChange(systemPropertyName, callback); } /** * Part of AudioService dump * @param pw Loading
services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -101,7 +101,7 @@ public class AbsoluteVolumeBehaviorTest { mAudioService = new AudioService(mContext, mSpyAudioSystem, mSystemServer, mSettingsAdapter, mAudioVolumeGroupHelper, mMockAudioPolicy, mTestLooper.getLooper(), mock(AppOpsManager.class), mock(PermissionEnforcer.class), mock(AudioServerPermissionProvider.class), r -> r.run()) { mock(AudioServerPermissionProvider.class)) { @Override public int getDeviceForStream(int stream) { return AudioSystem.DEVICE_OUT_SPEAKER; Loading