Move Choreographer impl to new file.

Separates implementation from the API so it is neater.

Bug: 255838011
Test: make, flash, atest ChoreographerNativeTest

Change-Id: I8ac97ed4ebc1a4ed9d6315a473e178bf3d655252
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 539cbaa..e64165f 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -14,13 +14,10 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "Choreographer"
-//#define LOG_NDEBUG 0
-
 #include <android-base/thread_annotations.h>
 #include <android/gui/ISurfaceComposer.h>
-#include <gui/DisplayEventDispatcher.h>
 #include <jni.h>
+#include <nativedisplay/Choreographer.h>
 #include <private/android/choreographer.h>
 #include <utils/Looper.h>
 #include <utils/Timers.h>
@@ -31,444 +28,9 @@
 #include <queue>
 #include <thread>
 
-namespace {
-struct {
-    // Global JVM that is provided by zygote
-    JavaVM* jvm = nullptr;
-    struct {
-        jclass clazz;
-        jmethodID getInstance;
-        jmethodID registerNativeChoreographerForRefreshRateCallbacks;
-        jmethodID unregisterNativeChoreographerForRefreshRateCallbacks;
-    } displayManagerGlobal;
-} gJni;
+#undef LOG_TAG
+#define LOG_TAG "AChoreographer"
 
-// Gets the JNIEnv* for this thread, and performs one-off initialization if we
-// have never retrieved a JNIEnv* pointer before.
-JNIEnv* getJniEnv() {
-    if (gJni.jvm == nullptr) {
-        ALOGW("AChoreographer: No JVM provided!");
-        return nullptr;
-    }
-
-    JNIEnv* env = nullptr;
-    if (gJni.jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
-        ALOGD("Attaching thread to JVM for AChoreographer");
-        JavaVMAttachArgs args = {JNI_VERSION_1_4, "AChoreographer_env", NULL};
-        jint attachResult = gJni.jvm->AttachCurrentThreadAsDaemon(&env, (void*)&args);
-        if (attachResult != JNI_OK) {
-            ALOGE("Unable to attach thread. Error: %d", attachResult);
-            return nullptr;
-        }
-    }
-    if (env == nullptr) {
-        ALOGW("AChoreographer: No JNI env available!");
-    }
-    return env;
-}
-
-inline const char* toString(bool value) {
-    return value ? "true" : "false";
-}
-} // namespace
-
-namespace android {
-using gui::VsyncEventData;
-
-struct FrameCallback {
-    AChoreographer_frameCallback callback;
-    AChoreographer_frameCallback64 callback64;
-    AChoreographer_vsyncCallback vsyncCallback;
-    void* data;
-    nsecs_t dueTime;
-
-    inline bool operator<(const FrameCallback& rhs) const {
-        // Note that this is intentionally flipped because we want callbacks due sooner to be at
-        // the head of the queue
-        return dueTime > rhs.dueTime;
-    }
-};
-
-struct RefreshRateCallback {
-    AChoreographer_refreshRateCallback callback;
-    void* data;
-    bool firstCallbackFired = false;
-};
-
-class Choreographer;
-
-/**
- * Implementation of AChoreographerFrameCallbackData.
- */
-struct ChoreographerFrameCallbackDataImpl {
-    int64_t frameTimeNanos{0};
-
-    VsyncEventData vsyncEventData;
-
-    const Choreographer* choreographer;
-};
-
-struct {
-    std::mutex lock;
-    std::vector<Choreographer*> ptrs GUARDED_BY(lock);
-    std::map<AVsyncId, int64_t> startTimes GUARDED_BY(lock);
-    bool registeredToDisplayManager GUARDED_BY(lock) = false;
-
-    std::atomic<nsecs_t> mLastKnownVsync = -1;
-} gChoreographers;
-
-class Choreographer : public DisplayEventDispatcher, public MessageHandler {
-public:
-    explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock);
-    void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
-                                  AChoreographer_frameCallback64 cb64,
-                                  AChoreographer_vsyncCallback vsyncCallback, void* data,
-                                  nsecs_t delay);
-    void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data)
-            EXCLUDES(gChoreographers.lock);
-    void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
-    // Drains the queue of pending vsync periods and dispatches refresh rate
-    // updates to callbacks.
-    // The assumption is that this method is only called on a single
-    // processing thread, either by looper or by AChoreographer_handleEvents
-    void handleRefreshRateUpdates();
-    void scheduleLatestConfigRequest();
-
-    enum {
-        MSG_SCHEDULE_CALLBACKS = 0,
-        MSG_SCHEDULE_VSYNC = 1,
-        MSG_HANDLE_REFRESH_RATE_UPDATES = 2,
-    };
-    virtual void handleMessage(const Message& message) override;
-
-    static Choreographer* getForThread();
-    virtual ~Choreographer() override EXCLUDES(gChoreographers.lock);
-    int64_t getFrameInterval() const;
-    bool inCallback() const;
-
-private:
-    Choreographer(const Choreographer&) = delete;
-
-    void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
-                       VsyncEventData vsyncEventData) override;
-    void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
-    void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
-                             nsecs_t vsyncPeriod) override;
-    void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override;
-    void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
-                                    std::vector<FrameRateOverride> overrides) override;
-
-    void scheduleCallbacks();
-
-    ChoreographerFrameCallbackDataImpl createFrameCallbackData(nsecs_t timestamp) const;
-    void registerStartTime() const;
-
-    std::mutex mLock;
-    // Protected by mLock
-    std::priority_queue<FrameCallback> mFrameCallbacks;
-    std::vector<RefreshRateCallback> mRefreshRateCallbacks;
-
-    nsecs_t mLatestVsyncPeriod = -1;
-    VsyncEventData mLastVsyncEventData;
-    bool mInCallback = false;
-
-    const sp<Looper> mLooper;
-    const std::thread::id mThreadId;
-
-    // Approximation of num_threads_using_choreographer * num_frames_of_history with leeway.
-    static constexpr size_t kMaxStartTimes = 250;
-};
-
-static thread_local Choreographer* gChoreographer;
-Choreographer* Choreographer::getForThread() {
-    if (gChoreographer == nullptr) {
-        sp<Looper> looper = Looper::getForThread();
-        if (!looper.get()) {
-            ALOGW("No looper prepared for thread");
-            return nullptr;
-        }
-        gChoreographer = new Choreographer(looper);
-        status_t result = gChoreographer->initialize();
-        if (result != OK) {
-            ALOGW("Failed to initialize");
-            return nullptr;
-        }
-    }
-    return gChoreographer;
-}
-
-Choreographer::Choreographer(const sp<Looper>& looper)
-      : DisplayEventDispatcher(looper, gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp),
-        mLooper(looper),
-        mThreadId(std::this_thread::get_id()) {
-    std::lock_guard<std::mutex> _l(gChoreographers.lock);
-    gChoreographers.ptrs.push_back(this);
-}
-
-Choreographer::~Choreographer() {
-    std::lock_guard<std::mutex> _l(gChoreographers.lock);
-    gChoreographers.ptrs.erase(std::remove_if(gChoreographers.ptrs.begin(),
-                                              gChoreographers.ptrs.end(),
-                                              [=](Choreographer* c) { return c == this; }),
-                               gChoreographers.ptrs.end());
-    // Only poke DisplayManagerGlobal to unregister if we previously registered
-    // callbacks.
-    if (gChoreographers.ptrs.empty() && gChoreographers.registeredToDisplayManager) {
-        gChoreographers.registeredToDisplayManager = false;
-        JNIEnv* env = getJniEnv();
-        if (env == nullptr) {
-            ALOGW("JNI environment is unavailable, skipping choreographer cleanup");
-            return;
-        }
-        jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz,
-                                                  gJni.displayManagerGlobal.getInstance);
-        if (dmg == nullptr) {
-            ALOGW("DMS is not initialized yet, skipping choreographer cleanup");
-        } else {
-            env->CallVoidMethod(dmg,
-                                gJni.displayManagerGlobal
-                                        .unregisterNativeChoreographerForRefreshRateCallbacks);
-            env->DeleteLocalRef(dmg);
-        }
-    }
-}
-
-void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb,
-                                             AChoreographer_frameCallback64 cb64,
-                                             AChoreographer_vsyncCallback vsyncCallback, void* data,
-                                             nsecs_t delay) {
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    FrameCallback callback{cb, cb64, vsyncCallback, data, now + delay};
-    {
-        std::lock_guard<std::mutex> _l{mLock};
-        mFrameCallbacks.push(callback);
-    }
-    if (callback.dueTime <= now) {
-        if (std::this_thread::get_id() != mThreadId) {
-            if (mLooper != nullptr) {
-                Message m{MSG_SCHEDULE_VSYNC};
-                mLooper->sendMessage(this, m);
-            } else {
-                scheduleVsync();
-            }
-        } else {
-            scheduleVsync();
-        }
-    } else {
-        if (mLooper != nullptr) {
-            Message m{MSG_SCHEDULE_CALLBACKS};
-            mLooper->sendMessageDelayed(delay, this, m);
-        } else {
-            scheduleCallbacks();
-        }
-    }
-}
-
-void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) {
-    std::lock_guard<std::mutex> _l{mLock};
-    for (const auto& callback : mRefreshRateCallbacks) {
-        // Don't re-add callbacks.
-        if (cb == callback.callback && data == callback.data) {
-            return;
-        }
-    }
-    mRefreshRateCallbacks.emplace_back(
-            RefreshRateCallback{.callback = cb, .data = data, .firstCallbackFired = false});
-    bool needsRegistration = false;
-    {
-        std::lock_guard<std::mutex> _l2(gChoreographers.lock);
-        needsRegistration = !gChoreographers.registeredToDisplayManager;
-    }
-    if (needsRegistration) {
-        JNIEnv* env = getJniEnv();
-        if (env == nullptr) {
-            ALOGW("JNI environment is unavailable, skipping registration");
-            return;
-        }
-        jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz,
-                                                  gJni.displayManagerGlobal.getInstance);
-        if (dmg == nullptr) {
-            ALOGW("DMS is not initialized yet: skipping registration");
-            return;
-        } else {
-            env->CallVoidMethod(dmg,
-                                gJni.displayManagerGlobal
-                                        .registerNativeChoreographerForRefreshRateCallbacks,
-                                reinterpret_cast<int64_t>(this));
-            env->DeleteLocalRef(dmg);
-            {
-                std::lock_guard<std::mutex> _l2(gChoreographers.lock);
-                gChoreographers.registeredToDisplayManager = true;
-            }
-        }
-    } else {
-        scheduleLatestConfigRequest();
-    }
-}
-
-void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb,
-                                                  void* data) {
-    std::lock_guard<std::mutex> _l{mLock};
-    mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(),
-                                               mRefreshRateCallbacks.end(),
-                                               [&](const RefreshRateCallback& callback) {
-                                                   return cb == callback.callback &&
-                                                           data == callback.data;
-                                               }),
-                                mRefreshRateCallbacks.end());
-}
-
-void Choreographer::scheduleLatestConfigRequest() {
-    if (mLooper != nullptr) {
-        Message m{MSG_HANDLE_REFRESH_RATE_UPDATES};
-        mLooper->sendMessage(this, m);
-    } else {
-        // If the looper thread is detached from Choreographer, then refresh rate
-        // changes will be handled in AChoreographer_handlePendingEvents, so we
-        // need to wake up the looper thread by writing to the write-end of the
-        // socket the looper is listening on.
-        // Fortunately, these events are small so sending packets across the
-        // socket should be atomic across processes.
-        DisplayEventReceiver::Event event;
-        event.header =
-                DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL,
-                                                    PhysicalDisplayId::fromPort(0), systemTime()};
-        injectEvent(event);
-    }
-}
-
-void Choreographer::scheduleCallbacks() {
-    const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    nsecs_t dueTime;
-    {
-        std::lock_guard<std::mutex> _l{mLock};
-        // If there are no pending callbacks then don't schedule a vsync
-        if (mFrameCallbacks.empty()) {
-            return;
-        }
-        dueTime = mFrameCallbacks.top().dueTime;
-    }
-
-    if (dueTime <= now) {
-        ALOGV("choreographer %p ~ scheduling vsync", this);
-        scheduleVsync();
-        return;
-    }
-}
-
-void Choreographer::handleRefreshRateUpdates() {
-    std::vector<RefreshRateCallback> callbacks{};
-    const nsecs_t pendingPeriod = gChoreographers.mLastKnownVsync.load();
-    const nsecs_t lastPeriod = mLatestVsyncPeriod;
-    if (pendingPeriod > 0) {
-        mLatestVsyncPeriod = pendingPeriod;
-    }
-    {
-        std::lock_guard<std::mutex> _l{mLock};
-        for (auto& cb : mRefreshRateCallbacks) {
-            callbacks.push_back(cb);
-            cb.firstCallbackFired = true;
-        }
-    }
-
-    for (auto& cb : callbacks) {
-        if (!cb.firstCallbackFired || (pendingPeriod > 0 && pendingPeriod != lastPeriod)) {
-            cb.callback(pendingPeriod, cb.data);
-        }
-    }
-}
-
-// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
-// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
-// the internal display implicitly.
-void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t,
-                                  VsyncEventData vsyncEventData) {
-    std::vector<FrameCallback> callbacks{};
-    {
-        std::lock_guard<std::mutex> _l{mLock};
-        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-        while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
-            callbacks.push_back(mFrameCallbacks.top());
-            mFrameCallbacks.pop();
-        }
-    }
-    mLastVsyncEventData = vsyncEventData;
-    for (const auto& cb : callbacks) {
-        if (cb.vsyncCallback != nullptr) {
-            const ChoreographerFrameCallbackDataImpl frameCallbackData =
-                    createFrameCallbackData(timestamp);
-            registerStartTime();
-            mInCallback = true;
-            cb.vsyncCallback(reinterpret_cast<const AChoreographerFrameCallbackData*>(
-                                     &frameCallbackData),
-                             cb.data);
-            mInCallback = false;
-        } else if (cb.callback64 != nullptr) {
-            cb.callback64(timestamp, cb.data);
-        } else if (cb.callback != nullptr) {
-            cb.callback(timestamp, cb.data);
-        }
-    }
-}
-
-void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
-    ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.", this,
-          to_string(displayId).c_str(), toString(connected));
-}
-
-void Choreographer::dispatchModeChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) {
-    LOG_ALWAYS_FATAL("dispatchModeChanged was called but was never registered");
-}
-
-void Choreographer::dispatchFrameRateOverrides(nsecs_t, PhysicalDisplayId,
-                                               std::vector<FrameRateOverride>) {
-    LOG_ALWAYS_FATAL("dispatchFrameRateOverrides was called but was never registered");
-}
-
-void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) {
-    ALOGV("choreographer %p ~ received null event.", this);
-    handleRefreshRateUpdates();
-}
-
-void Choreographer::handleMessage(const Message& message) {
-    switch (message.what) {
-        case MSG_SCHEDULE_CALLBACKS:
-            scheduleCallbacks();
-            break;
-        case MSG_SCHEDULE_VSYNC:
-            scheduleVsync();
-            break;
-        case MSG_HANDLE_REFRESH_RATE_UPDATES:
-            handleRefreshRateUpdates();
-            break;
-    }
-}
-
-int64_t Choreographer::getFrameInterval() const {
-    return mLastVsyncEventData.frameInterval;
-}
-
-bool Choreographer::inCallback() const {
-    return mInCallback;
-}
-
-ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const {
-    return {.frameTimeNanos = timestamp,
-            .vsyncEventData = mLastVsyncEventData,
-            .choreographer = this};
-}
-
-void Choreographer::registerStartTime() const {
-    std::scoped_lock _l(gChoreographers.lock);
-    for (VsyncEventData::FrameTimeline frameTimeline : mLastVsyncEventData.frameTimelines) {
-        while (gChoreographers.startTimes.size() >= kMaxStartTimes) {
-            gChoreographers.startTimes.erase(gChoreographers.startTimes.begin());
-        }
-        gChoreographers.startTimes[frameTimeline.vsyncId] = systemTime(SYSTEM_TIME_MONOTONIC);
-    }
-}
-
-} // namespace android
 using namespace android;
 
 static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
@@ -488,27 +50,12 @@
 
 // Glue for private C api
 namespace android {
-void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) {
-    std::lock_guard<std::mutex> _l(gChoreographers.lock);
-    gChoreographers.mLastKnownVsync.store(vsyncPeriod);
-    for (auto c : gChoreographers.ptrs) {
-        c->scheduleLatestConfigRequest();
-    }
+void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) {
+    Choreographer::signalRefreshRateCallbacks(vsyncPeriod);
 }
 
 void AChoreographer_initJVM(JNIEnv* env) {
-    env->GetJavaVM(&gJni.jvm);
-    // Now we need to find the java classes.
-    jclass dmgClass = env->FindClass("android/hardware/display/DisplayManagerGlobal");
-    gJni.displayManagerGlobal.clazz = static_cast<jclass>(env->NewGlobalRef(dmgClass));
-    gJni.displayManagerGlobal.getInstance =
-            env->GetStaticMethodID(dmgClass, "getInstance",
-                                   "()Landroid/hardware/display/DisplayManagerGlobal;");
-    gJni.displayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks =
-            env->GetMethodID(dmgClass, "registerNativeChoreographerForRefreshRateCallbacks", "()V");
-    gJni.displayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks =
-            env->GetMethodID(dmgClass, "unregisterNativeChoreographerForRefreshRateCallbacks",
-                             "()V");
+    Choreographer::initJVM(env);
 }
 
 AChoreographer* AChoreographer_routeGetInstance() {
@@ -583,13 +130,7 @@
 }
 
 int64_t AChoreographer_getStartTimeNanosForVsyncId(AVsyncId vsyncId) {
-    std::scoped_lock _l(gChoreographers.lock);
-    const auto iter = gChoreographers.startTimes.find(vsyncId);
-    if (iter == gChoreographers.startTimes.end()) {
-        ALOGW("Start time was not found for vsync id: %" PRId64, vsyncId);
-        return 0;
-    }
-    return iter->second;
+    return Choreographer::getStartTimeNanosForVsyncId(vsyncId);
 }
 
 } // namespace android