Loading core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ cc_library_shared_for_libandroid_runtime { "libtracing_perfetto", "libharfbuzz_ng", "liblog", "libmediautils", "libminikin", "libz", "server_configurable_flags", Loading core/jni/android_media_AudioSystem.cpp +57 −27 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #include <atomic> #define LOG_TAG "AudioSystem-JNI" #include <android/binder_ibinder_jni.h> #include <android/binder_libbinder.h> Loading @@ -34,15 +35,16 @@ #include <media/AudioContainers.h> #include <media/AudioPolicy.h> #include <media/AudioSystem.h> #include <mediautils/jthread.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedLocalRef.h> #include <nativehelper/ScopedPrimitiveArray.h> #include <nativehelper/jni_macros.h> #include <system/audio.h> #include <system/audio_policy.h> #include <sys/system_properties.h> #include <utils/Log.h> #include <thread> #include <optional> #include <sstream> #include <memory> Loading @@ -57,6 +59,7 @@ #include "android_media_AudioMixerAttributes.h" #include "android_media_AudioProfile.h" #include "android_media_MicrophoneInfo.h" #include "android_media_JNIUtils.h" #include "android_util_Binder.h" #include "core_jni_helpers.h" Loading Loading @@ -3375,42 +3378,53 @@ static jboolean android_media_AudioSystem_isBluetoothVariableLatencyEnabled(JNIE 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); mCallback {javaCallback, env}, mPi {__system_property_find(sysPropName.c_str())}, mListenerThread([this](mediautils::stop_token stok) mutable { static const struct timespec close_delay = { .tv_sec = 1 }; while (!stok.stop_requested()) { uint32_t old_serial = mSerial.load(); uint32_t new_serial; if (__system_property_wait(mPi, old_serial, &new_serial, &close_delay)) { while (new_serial > old_serial) { if (mSerial.compare_exchange_weak(old_serial, new_serial)) { fireUpdate(); break; } } } }); } }) {} ~JavaSystemPropertyListener() { mCleanupSignal.store(true); mListenerThread.join(); JNIEnv* env = GetOrAttachJNIEnvironment(gVm); env->DeleteGlobalRef(mCallback); void triggerUpdateIfChanged() { uint32_t old_serial = mSerial.load(); uint32_t new_serial = __system_property_serial(mPi); while (new_serial > old_serial) { if (mSerial.compare_exchange_weak(old_serial, new_serial)) { fireUpdate(); break; } } } private: jobject mCallback; android::base::CachedProperty mCachedProperty; std::thread mListenerThread; std::atomic<bool> mCleanupSignal{false}; std::string mLastVal = ""; void fireUpdate() { const auto threadEnv = GetOrAttachJNIEnvironment(gVm); threadEnv->CallVoidMethod(mCallback.get(), gRunnableClassInfo.run); } // Should outlive thread object const GlobalRef mCallback; const prop_info * const mPi; std::atomic<uint32_t> mSerial = 0; const mediautils::jthread mListenerThread; }; // A logical set keyed by address std::vector<std::unique_ptr<JavaSystemPropertyListener>> gSystemPropertyListeners; std::mutex gSysPropLock{}; static void android_media_AudioSystem_listenForSystemPropertyChange(JNIEnv *env, jobject thiz, static jlong android_media_AudioSystem_listenForSystemPropertyChange(JNIEnv *env, jobject thiz, jstring sysProp, jobject javaCallback) { ScopedUtfChars sysPropChars{env, sysProp}; Loading @@ -3418,6 +3432,19 @@ static void android_media_AudioSystem_listenForSystemPropertyChange(JNIEnv *env, std::string{sysPropChars.c_str()}); std::unique_lock _l{gSysPropLock}; gSystemPropertyListeners.push_back(std::move(listener)); return reinterpret_cast<jlong>(gSystemPropertyListeners.back().get()); } static void android_media_AudioSystem_triggerSystemPropertyUpdate(JNIEnv *env, jobject thiz, jlong nativeHandle) { std::unique_lock _l{gSysPropLock}; const auto iter = std::find_if(gSystemPropertyListeners.begin(), gSystemPropertyListeners.end(), [nativeHandle](const auto& x) { return reinterpret_cast<jlong>(x.get()) == nativeHandle; }); if (iter != gSystemPropertyListeners.end()) { (*iter)->triggerUpdateIfChanged(); } else { jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid handle"); } } Loading Loading @@ -3595,8 +3622,11 @@ static const JNINativeMethod gMethods[] = MAKE_AUDIO_SYSTEM_METHOD(setBluetoothVariableLatencyEnabled), MAKE_AUDIO_SYSTEM_METHOD(isBluetoothVariableLatencyEnabled), MAKE_JNI_NATIVE_METHOD("listenForSystemPropertyChange", "(Ljava/lang/String;Ljava/lang/Runnable;)V", "(Ljava/lang/String;Ljava/lang/Runnable;)J", android_media_AudioSystem_listenForSystemPropertyChange), MAKE_JNI_NATIVE_METHOD("triggerSystemPropertyUpdate", "(J)V", android_media_AudioSystem_triggerSystemPropertyUpdate), }; Loading media/java/android/media/AudioSystem.java +10 −1 Original line number Diff line number Diff line Loading @@ -2655,7 +2655,16 @@ public class AudioSystem /** * Register a native listener for system property sysprop * @param callback the listener which fires when the property changes * @return a native handle for use in subsequent methods * @hide */ public static native void listenForSystemPropertyChange(String sysprop, Runnable callback); public static native long listenForSystemPropertyChange(String sysprop, Runnable callback); /** * Trigger a sysprop listener update, if the property has been updated: synchronously validating * there are no pending sysprop changes. * @param handle the handle returned by {@link listenForSystemPropertyChange} * @hide */ public static native void triggerSystemPropertyUpdate(long handle); } services/core/java/com/android/server/audio/AudioService.java +3 −1 Original line number Diff line number Diff line Loading @@ -790,6 +790,7 @@ public class AudioService extends IAudioService.Stub private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); private final Executor mAudioServerLifecycleExecutor; private long mSysPropListenerNativeHandle; private final List<Future> mScheduledPermissionTasks = new ArrayList(); private IMediaProjectionManager mProjectionService; // to validate projection token Loading Loading @@ -10640,7 +10641,7 @@ public class AudioService extends IAudioService.Stub }, UPDATE_DELAY_MS, TimeUnit.MILLISECONDS)); } }; mAudioSystem.listenForSystemPropertyChange( mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO, task); } else { Loading Loading @@ -14713,6 +14714,7 @@ public class AudioService extends IAudioService.Stub @Override /** @see AudioManager#permissionUpdateBarrier() */ public void permissionUpdateBarrier() { mAudioSystem.triggerSystemPropertyUpdate(mSysPropListenerNativeHandle); List<Future> snapshot; synchronized (mScheduledPermissionTasks) { snapshot = List.copyOf(mScheduledPermissionTasks); services/core/java/com/android/server/audio/AudioSystemAdapter.java +6 −2 Original line number Diff line number Diff line Loading @@ -748,8 +748,12 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback, return AudioSystem.setMasterMute(mute); } public void listenForSystemPropertyChange(String systemPropertyName, Runnable callback) { AudioSystem.listenForSystemPropertyChange(systemPropertyName, callback); public long listenForSystemPropertyChange(String systemPropertyName, Runnable callback) { return AudioSystem.listenForSystemPropertyChange(systemPropertyName, callback); } public void triggerSystemPropertyUpdate(long handle) { AudioSystem.triggerSystemPropertyUpdate(handle); } /** Loading Loading
core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ cc_library_shared_for_libandroid_runtime { "libtracing_perfetto", "libharfbuzz_ng", "liblog", "libmediautils", "libminikin", "libz", "server_configurable_flags", Loading
core/jni/android_media_AudioSystem.cpp +57 −27 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #include <atomic> #define LOG_TAG "AudioSystem-JNI" #include <android/binder_ibinder_jni.h> #include <android/binder_libbinder.h> Loading @@ -34,15 +35,16 @@ #include <media/AudioContainers.h> #include <media/AudioPolicy.h> #include <media/AudioSystem.h> #include <mediautils/jthread.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedLocalRef.h> #include <nativehelper/ScopedPrimitiveArray.h> #include <nativehelper/jni_macros.h> #include <system/audio.h> #include <system/audio_policy.h> #include <sys/system_properties.h> #include <utils/Log.h> #include <thread> #include <optional> #include <sstream> #include <memory> Loading @@ -57,6 +59,7 @@ #include "android_media_AudioMixerAttributes.h" #include "android_media_AudioProfile.h" #include "android_media_MicrophoneInfo.h" #include "android_media_JNIUtils.h" #include "android_util_Binder.h" #include "core_jni_helpers.h" Loading Loading @@ -3375,42 +3378,53 @@ static jboolean android_media_AudioSystem_isBluetoothVariableLatencyEnabled(JNIE 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); mCallback {javaCallback, env}, mPi {__system_property_find(sysPropName.c_str())}, mListenerThread([this](mediautils::stop_token stok) mutable { static const struct timespec close_delay = { .tv_sec = 1 }; while (!stok.stop_requested()) { uint32_t old_serial = mSerial.load(); uint32_t new_serial; if (__system_property_wait(mPi, old_serial, &new_serial, &close_delay)) { while (new_serial > old_serial) { if (mSerial.compare_exchange_weak(old_serial, new_serial)) { fireUpdate(); break; } } } }); } }) {} ~JavaSystemPropertyListener() { mCleanupSignal.store(true); mListenerThread.join(); JNIEnv* env = GetOrAttachJNIEnvironment(gVm); env->DeleteGlobalRef(mCallback); void triggerUpdateIfChanged() { uint32_t old_serial = mSerial.load(); uint32_t new_serial = __system_property_serial(mPi); while (new_serial > old_serial) { if (mSerial.compare_exchange_weak(old_serial, new_serial)) { fireUpdate(); break; } } } private: jobject mCallback; android::base::CachedProperty mCachedProperty; std::thread mListenerThread; std::atomic<bool> mCleanupSignal{false}; std::string mLastVal = ""; void fireUpdate() { const auto threadEnv = GetOrAttachJNIEnvironment(gVm); threadEnv->CallVoidMethod(mCallback.get(), gRunnableClassInfo.run); } // Should outlive thread object const GlobalRef mCallback; const prop_info * const mPi; std::atomic<uint32_t> mSerial = 0; const mediautils::jthread mListenerThread; }; // A logical set keyed by address std::vector<std::unique_ptr<JavaSystemPropertyListener>> gSystemPropertyListeners; std::mutex gSysPropLock{}; static void android_media_AudioSystem_listenForSystemPropertyChange(JNIEnv *env, jobject thiz, static jlong android_media_AudioSystem_listenForSystemPropertyChange(JNIEnv *env, jobject thiz, jstring sysProp, jobject javaCallback) { ScopedUtfChars sysPropChars{env, sysProp}; Loading @@ -3418,6 +3432,19 @@ static void android_media_AudioSystem_listenForSystemPropertyChange(JNIEnv *env, std::string{sysPropChars.c_str()}); std::unique_lock _l{gSysPropLock}; gSystemPropertyListeners.push_back(std::move(listener)); return reinterpret_cast<jlong>(gSystemPropertyListeners.back().get()); } static void android_media_AudioSystem_triggerSystemPropertyUpdate(JNIEnv *env, jobject thiz, jlong nativeHandle) { std::unique_lock _l{gSysPropLock}; const auto iter = std::find_if(gSystemPropertyListeners.begin(), gSystemPropertyListeners.end(), [nativeHandle](const auto& x) { return reinterpret_cast<jlong>(x.get()) == nativeHandle; }); if (iter != gSystemPropertyListeners.end()) { (*iter)->triggerUpdateIfChanged(); } else { jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid handle"); } } Loading Loading @@ -3595,8 +3622,11 @@ static const JNINativeMethod gMethods[] = MAKE_AUDIO_SYSTEM_METHOD(setBluetoothVariableLatencyEnabled), MAKE_AUDIO_SYSTEM_METHOD(isBluetoothVariableLatencyEnabled), MAKE_JNI_NATIVE_METHOD("listenForSystemPropertyChange", "(Ljava/lang/String;Ljava/lang/Runnable;)V", "(Ljava/lang/String;Ljava/lang/Runnable;)J", android_media_AudioSystem_listenForSystemPropertyChange), MAKE_JNI_NATIVE_METHOD("triggerSystemPropertyUpdate", "(J)V", android_media_AudioSystem_triggerSystemPropertyUpdate), }; Loading
media/java/android/media/AudioSystem.java +10 −1 Original line number Diff line number Diff line Loading @@ -2655,7 +2655,16 @@ public class AudioSystem /** * Register a native listener for system property sysprop * @param callback the listener which fires when the property changes * @return a native handle for use in subsequent methods * @hide */ public static native void listenForSystemPropertyChange(String sysprop, Runnable callback); public static native long listenForSystemPropertyChange(String sysprop, Runnable callback); /** * Trigger a sysprop listener update, if the property has been updated: synchronously validating * there are no pending sysprop changes. * @param handle the handle returned by {@link listenForSystemPropertyChange} * @hide */ public static native void triggerSystemPropertyUpdate(long handle); }
services/core/java/com/android/server/audio/AudioService.java +3 −1 Original line number Diff line number Diff line Loading @@ -790,6 +790,7 @@ public class AudioService extends IAudioService.Stub private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); private final Executor mAudioServerLifecycleExecutor; private long mSysPropListenerNativeHandle; private final List<Future> mScheduledPermissionTasks = new ArrayList(); private IMediaProjectionManager mProjectionService; // to validate projection token Loading Loading @@ -10640,7 +10641,7 @@ public class AudioService extends IAudioService.Stub }, UPDATE_DELAY_MS, TimeUnit.MILLISECONDS)); } }; mAudioSystem.listenForSystemPropertyChange( mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO, task); } else { Loading Loading @@ -14713,6 +14714,7 @@ public class AudioService extends IAudioService.Stub @Override /** @see AudioManager#permissionUpdateBarrier() */ public void permissionUpdateBarrier() { mAudioSystem.triggerSystemPropertyUpdate(mSysPropListenerNativeHandle); List<Future> snapshot; synchronized (mScheduledPermissionTasks) { snapshot = List.copyOf(mScheduledPermissionTasks);
services/core/java/com/android/server/audio/AudioSystemAdapter.java +6 −2 Original line number Diff line number Diff line Loading @@ -748,8 +748,12 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback, return AudioSystem.setMasterMute(mute); } public void listenForSystemPropertyChange(String systemPropertyName, Runnable callback) { AudioSystem.listenForSystemPropertyChange(systemPropertyName, callback); public long listenForSystemPropertyChange(String systemPropertyName, Runnable callback) { return AudioSystem.listenForSystemPropertyChange(systemPropertyName, callback); } public void triggerSystemPropertyUpdate(long handle) { AudioSystem.triggerSystemPropertyUpdate(handle); } /** Loading