summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/android_media_AudioSystem.cpp84
-rw-r--r--media/java/android/media/AudioSystem.java11
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioSystemAdapter.java8
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);
}
/**