diff options
| -rw-r--r-- | core/jni/Android.bp | 1 | ||||
| -rw-r--r-- | core/jni/android_media_AudioSystem.cpp | 84 | ||||
| -rw-r--r-- | media/java/android/media/AudioSystem.java | 11 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioService.java | 4 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioSystemAdapter.java | 8 |
5 files changed, 77 insertions, 31 deletions
diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 2abdd57662eb..90cb10aa62b2 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -108,6 +108,7 @@ cc_library_shared_for_libandroid_runtime { "libtracing_perfetto", "libharfbuzz_ng", "liblog", + "libmediautils", "libminikin", "libz", "server_configurable_flags", diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 638591f130ab..46710b5d3edc 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -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> @@ -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> @@ -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" @@ -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; + } + } + } } + }) {} + + 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; } - }); + } } - ~JavaSystemPropertyListener() { - mCleanupSignal.store(true); - mListenerThread.join(); - JNIEnv* env = GetOrAttachJNIEnvironment(gVm); - env->DeleteGlobalRef(mCallback); + private: + void fireUpdate() { + const auto threadEnv = GetOrAttachJNIEnvironment(gVm); + threadEnv->CallVoidMethod(mCallback.get(), gRunnableClassInfo.run); } - private: - jobject mCallback; - android::base::CachedProperty mCachedProperty; - std::thread mListenerThread; - std::atomic<bool> mCleanupSignal{false}; - std::string mLastVal = ""; + // 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}; @@ -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"); + } } @@ -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), }; diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index a255f730b0f3..ebdfd3e41aa1 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -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); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index b2b6764ead37..afa28cd6b0df 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -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 @@ -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 { @@ -14708,6 +14709,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); diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java index d083c68c4c2c..5cabddea9c17 100644 --- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java +++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java @@ -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); } /** |