Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68a8da47 authored by Atneya Nair's avatar Atneya Nair Committed by Android (Google) Code Review
Browse files

Merge "audio: Add addtl permission sync behavior" into main

parents 42452428 0620de1c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@ cc_library_shared_for_libandroid_runtime {
        "libtracing_perfetto",
        "libharfbuzz_ng",
        "liblog",
        "libmediautils",
        "libminikin",
        "libz",
        "server_configurable_flags",
+57 −27
Original line number Diff line number Diff line
@@ -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;
                            }
                        }
                    }
            });
                }
            }) {}

    ~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};
@@ -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),

        };

+10 −1
Original line number Diff line number Diff line
@@ -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);
}
+3 −1
Original line number Diff line number Diff line
@@ -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 {
@@ -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);
+6 −2
Original line number Diff line number Diff line
@@ -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);
    }

    /**