| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2015 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
 | 17 | #define LOG_TAG "Choreographer" | 
 | 18 | //#define LOG_NDEBUG 0 | 
 | 19 |  | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 20 | #include <android-base/thread_annotations.h> | 
| Alec Mouri | 77a5387 | 2019-10-28 16:44:36 -0700 | [diff] [blame] | 21 | #include <gui/DisplayEventDispatcher.h> | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 22 | #include <gui/ISurfaceComposer.h> | 
 | 23 | #include <gui/SurfaceComposerClient.h> | 
| Orion Hodson | e53587b | 2021-02-02 15:33:33 +0000 | [diff] [blame] | 24 | #include <jni.h> | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 25 | #include <private/android/choreographer.h> | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 26 | #include <utils/Looper.h> | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 27 | #include <utils/Timers.h> | 
 | 28 |  | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 29 | #include <cinttypes> | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 30 | #include <mutex> | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 31 | #include <optional> | 
 | 32 | #include <queue> | 
 | 33 | #include <thread> | 
 | 34 |  | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 35 | namespace { | 
 | 36 | struct { | 
 | 37 |     // Global JVM that is provided by zygote | 
 | 38 |     JavaVM* jvm = nullptr; | 
 | 39 |     struct { | 
 | 40 |         jclass clazz; | 
 | 41 |         jmethodID getInstance; | 
 | 42 |         jmethodID registerNativeChoreographerForRefreshRateCallbacks; | 
 | 43 |         jmethodID unregisterNativeChoreographerForRefreshRateCallbacks; | 
 | 44 |     } displayManagerGlobal; | 
 | 45 | } gJni; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 46 |  | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 47 | // Gets the JNIEnv* for this thread, and performs one-off initialization if we | 
 | 48 | // have never retrieved a JNIEnv* pointer before. | 
 | 49 | JNIEnv* getJniEnv() { | 
 | 50 |     if (gJni.jvm == nullptr) { | 
 | 51 |         ALOGW("AChoreographer: No JVM provided!"); | 
 | 52 |         return nullptr; | 
 | 53 |     } | 
 | 54 |  | 
 | 55 |     JNIEnv* env = nullptr; | 
 | 56 |     if (gJni.jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) { | 
 | 57 |         ALOGD("Attaching thread to JVM for AChoreographer"); | 
 | 58 |         JavaVMAttachArgs args = {JNI_VERSION_1_4, "AChoreographer_env", NULL}; | 
 | 59 |         jint attachResult = gJni.jvm->AttachCurrentThreadAsDaemon(&env, (void*)&args); | 
 | 60 |         if (attachResult != JNI_OK) { | 
 | 61 |             ALOGE("Unable to attach thread. Error: %d", attachResult); | 
 | 62 |             return nullptr; | 
 | 63 |         } | 
 | 64 |     } | 
 | 65 |     if (env == nullptr) { | 
 | 66 |         ALOGW("AChoreographer: No JNI env available!"); | 
 | 67 |     } | 
 | 68 |     return env; | 
 | 69 | } | 
 | 70 |  | 
 | 71 | inline const char* toString(bool value) { | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 72 |     return value ? "true" : "false"; | 
 | 73 | } | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 74 | } // namespace | 
 | 75 |  | 
 | 76 | namespace android { | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 77 |  | 
 | 78 | struct FrameCallback { | 
 | 79 |     AChoreographer_frameCallback callback; | 
 | 80 |     AChoreographer_frameCallback64 callback64; | 
 | 81 |     void* data; | 
 | 82 |     nsecs_t dueTime; | 
 | 83 |  | 
 | 84 |     inline bool operator<(const FrameCallback& rhs) const { | 
 | 85 |         // Note that this is intentionally flipped because we want callbacks due sooner to be at | 
 | 86 |         // the head of the queue | 
 | 87 |         return dueTime > rhs.dueTime; | 
 | 88 |     } | 
 | 89 | }; | 
 | 90 |  | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 91 | struct RefreshRateCallback { | 
 | 92 |     AChoreographer_refreshRateCallback callback; | 
 | 93 |     void* data; | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 94 |     bool firstCallbackFired = false; | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 95 | }; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 96 |  | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 97 | class Choreographer; | 
 | 98 |  | 
 | 99 | struct { | 
 | 100 |     std::mutex lock; | 
 | 101 |     std::vector<Choreographer*> ptrs GUARDED_BY(lock); | 
 | 102 |     bool registeredToDisplayManager GUARDED_BY(lock) = false; | 
 | 103 |  | 
 | 104 |     std::atomic<nsecs_t> mLastKnownVsync = -1; | 
 | 105 | } gChoreographers; | 
 | 106 |  | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 107 | class Choreographer : public DisplayEventDispatcher, public MessageHandler { | 
 | 108 | public: | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 109 |     explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock); | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 110 |     void postFrameCallbackDelayed(AChoreographer_frameCallback cb, | 
 | 111 |                                   AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay); | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 112 |     void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) | 
 | 113 |             EXCLUDES(gChoreographers.lock); | 
| Alec Mouri | 33682e9 | 2020-01-10 15:11:15 -0800 | [diff] [blame] | 114 |     void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data); | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 115 |     // Drains the queue of pending vsync periods and dispatches refresh rate | 
 | 116 |     // updates to callbacks. | 
 | 117 |     // The assumption is that this method is only called on a single | 
 | 118 |     // processing thread, either by looper or by AChoreographer_handleEvents | 
 | 119 |     void handleRefreshRateUpdates(); | 
 | 120 |     void scheduleLatestConfigRequest(); | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 121 |  | 
 | 122 |     enum { | 
 | 123 |         MSG_SCHEDULE_CALLBACKS = 0, | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 124 |         MSG_SCHEDULE_VSYNC = 1, | 
 | 125 |         MSG_HANDLE_REFRESH_RATE_UPDATES = 2, | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 126 |     }; | 
 | 127 |     virtual void handleMessage(const Message& message) override; | 
 | 128 |  | 
 | 129 |     static Choreographer* getForThread(); | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 130 |     virtual ~Choreographer() override EXCLUDES(gChoreographers.lock); | 
| Ady Abraham | 74e1756 | 2020-08-24 18:18:19 -0700 | [diff] [blame] | 131 |     int64_t getVsyncId() const; | 
| Ady Abraham | 0d28d76 | 2020-10-05 17:50:41 -0700 | [diff] [blame] | 132 |     int64_t getFrameDeadline() const; | 
| Ady Abraham | 74e1756 | 2020-08-24 18:18:19 -0700 | [diff] [blame] | 133 |  | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 134 |  | 
 | 135 | private: | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 136 |     Choreographer(const Choreographer&) = delete; | 
 | 137 |  | 
| Ady Abraham | 74e1756 | 2020-08-24 18:18:19 -0700 | [diff] [blame] | 138 |     void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, | 
| Ady Abraham | 0d28d76 | 2020-10-05 17:50:41 -0700 | [diff] [blame] | 139 |                        VsyncEventData vsyncEventData) override; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 140 |     void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override; | 
| Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 141 |     void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId, | 
 | 142 |                              nsecs_t vsyncPeriod) override; | 
| Alec Mouri | 967d5d7 | 2020-08-05 12:50:03 -0700 | [diff] [blame] | 143 |     void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override; | 
| Ady Abraham | 62f216c | 2020-10-13 19:07:23 -0700 | [diff] [blame] | 144 |     void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId, | 
 | 145 |                                     std::vector<FrameRateOverride> overrides) override; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 146 |  | 
 | 147 |     void scheduleCallbacks(); | 
 | 148 |  | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 149 |     std::mutex mLock; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 150 |     // Protected by mLock | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 151 |     std::priority_queue<FrameCallback> mFrameCallbacks; | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 152 |     std::vector<RefreshRateCallback> mRefreshRateCallbacks; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 153 |  | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 154 |     nsecs_t mLatestVsyncPeriod = -1; | 
| Ady Abraham | 0d28d76 | 2020-10-05 17:50:41 -0700 | [diff] [blame] | 155 |     VsyncEventData mLastVsyncEventData; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 156 |  | 
 | 157 |     const sp<Looper> mLooper; | 
 | 158 |     const std::thread::id mThreadId; | 
 | 159 | }; | 
 | 160 |  | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 161 | static thread_local Choreographer* gChoreographer; | 
 | 162 | Choreographer* Choreographer::getForThread() { | 
 | 163 |     if (gChoreographer == nullptr) { | 
 | 164 |         sp<Looper> looper = Looper::getForThread(); | 
 | 165 |         if (!looper.get()) { | 
 | 166 |             ALOGW("No looper prepared for thread"); | 
 | 167 |             return nullptr; | 
 | 168 |         } | 
 | 169 |         gChoreographer = new Choreographer(looper); | 
 | 170 |         status_t result = gChoreographer->initialize(); | 
 | 171 |         if (result != OK) { | 
 | 172 |             ALOGW("Failed to initialize"); | 
 | 173 |             return nullptr; | 
 | 174 |         } | 
 | 175 |     } | 
 | 176 |     return gChoreographer; | 
 | 177 | } | 
 | 178 |  | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 179 | Choreographer::Choreographer(const sp<Looper>& looper) | 
| Ady Abraham | 62f216c | 2020-10-13 19:07:23 -0700 | [diff] [blame] | 180 |       : DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp), | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 181 |         mLooper(looper), | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 182 |         mThreadId(std::this_thread::get_id()) { | 
 | 183 |     std::lock_guard<std::mutex> _l(gChoreographers.lock); | 
 | 184 |     gChoreographers.ptrs.push_back(this); | 
 | 185 | } | 
 | 186 |  | 
 | 187 | Choreographer::~Choreographer() { | 
 | 188 |     std::lock_guard<std::mutex> _l(gChoreographers.lock); | 
 | 189 |     gChoreographers.ptrs.erase(std::remove_if(gChoreographers.ptrs.begin(), | 
 | 190 |                                               gChoreographers.ptrs.end(), | 
 | 191 |                                               [=](Choreographer* c) { return c == this; }), | 
 | 192 |                                gChoreographers.ptrs.end()); | 
 | 193 |     // Only poke DisplayManagerGlobal to unregister if we previously registered | 
 | 194 |     // callbacks. | 
 | 195 |     if (gChoreographers.ptrs.empty() && gChoreographers.registeredToDisplayManager) { | 
 | 196 |         JNIEnv* env = getJniEnv(); | 
 | 197 |         if (env == nullptr) { | 
 | 198 |             ALOGW("JNI environment is unavailable, skipping choreographer cleanup"); | 
 | 199 |             return; | 
 | 200 |         } | 
 | 201 |         jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz, | 
 | 202 |                                                   gJni.displayManagerGlobal.getInstance); | 
 | 203 |         if (dmg == nullptr) { | 
 | 204 |             ALOGW("DMS is not initialized yet, skipping choreographer cleanup"); | 
 | 205 |         } else { | 
 | 206 |             env->CallVoidMethod(dmg, | 
 | 207 |                                 gJni.displayManagerGlobal | 
 | 208 |                                         .unregisterNativeChoreographerForRefreshRateCallbacks); | 
 | 209 |             env->DeleteLocalRef(dmg); | 
 | 210 |         } | 
 | 211 |     } | 
 | 212 | } | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 213 |  | 
 | 214 | void Choreographer::postFrameCallbackDelayed( | 
 | 215 |         AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) { | 
 | 216 |     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); | 
 | 217 |     FrameCallback callback{cb, cb64, data, now + delay}; | 
 | 218 |     { | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 219 |         std::lock_guard<std::mutex> _l{mLock}; | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 220 |         mFrameCallbacks.push(callback); | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 221 |     } | 
 | 222 |     if (callback.dueTime <= now) { | 
 | 223 |         if (std::this_thread::get_id() != mThreadId) { | 
| Alec Mouri | 50a931d | 2019-11-19 16:23:59 -0800 | [diff] [blame] | 224 |             if (mLooper != nullptr) { | 
 | 225 |                 Message m{MSG_SCHEDULE_VSYNC}; | 
 | 226 |                 mLooper->sendMessage(this, m); | 
 | 227 |             } else { | 
 | 228 |                 scheduleVsync(); | 
 | 229 |             } | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 230 |         } else { | 
 | 231 |             scheduleVsync(); | 
 | 232 |         } | 
 | 233 |     } else { | 
| Alec Mouri | 50a931d | 2019-11-19 16:23:59 -0800 | [diff] [blame] | 234 |         if (mLooper != nullptr) { | 
 | 235 |             Message m{MSG_SCHEDULE_CALLBACKS}; | 
 | 236 |             mLooper->sendMessageDelayed(delay, this, m); | 
 | 237 |         } else { | 
 | 238 |             scheduleCallbacks(); | 
 | 239 |         } | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 240 |     } | 
 | 241 | } | 
 | 242 |  | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 243 | void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) { | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 244 |     std::lock_guard<std::mutex> _l{mLock}; | 
 | 245 |     for (const auto& callback : mRefreshRateCallbacks) { | 
 | 246 |         // Don't re-add callbacks. | 
 | 247 |         if (cb == callback.callback && data == callback.data) { | 
 | 248 |             return; | 
 | 249 |         } | 
 | 250 |     } | 
 | 251 |     mRefreshRateCallbacks.emplace_back( | 
 | 252 |             RefreshRateCallback{.callback = cb, .data = data, .firstCallbackFired = false}); | 
 | 253 |     bool needsRegistration = false; | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 254 |     { | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 255 |         std::lock_guard<std::mutex> _l2(gChoreographers.lock); | 
 | 256 |         needsRegistration = !gChoreographers.registeredToDisplayManager; | 
 | 257 |     } | 
 | 258 |     if (needsRegistration) { | 
 | 259 |         JNIEnv* env = getJniEnv(); | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 260 |         if (env == nullptr) { | 
| Greg Kaiser | b66d04b | 2020-05-11 06:52:15 -0700 | [diff] [blame] | 261 |             ALOGW("JNI environment is unavailable, skipping registration"); | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 262 |             return; | 
 | 263 |         } | 
| Greg Kaiser | b66d04b | 2020-05-11 06:52:15 -0700 | [diff] [blame] | 264 |         jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz, | 
 | 265 |                                                   gJni.displayManagerGlobal.getInstance); | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 266 |         if (dmg == nullptr) { | 
 | 267 |             ALOGW("DMS is not initialized yet: skipping registration"); | 
 | 268 |             return; | 
 | 269 |         } else { | 
 | 270 |             env->CallVoidMethod(dmg, | 
 | 271 |                                 gJni.displayManagerGlobal | 
 | 272 |                                         .registerNativeChoreographerForRefreshRateCallbacks, | 
 | 273 |                                 reinterpret_cast<int64_t>(this)); | 
 | 274 |             env->DeleteLocalRef(dmg); | 
 | 275 |             { | 
 | 276 |                 std::lock_guard<std::mutex> _l2(gChoreographers.lock); | 
 | 277 |                 gChoreographers.registeredToDisplayManager = true; | 
| Alec Mouri | 33682e9 | 2020-01-10 15:11:15 -0800 | [diff] [blame] | 278 |             } | 
 | 279 |         } | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 280 |     } else { | 
 | 281 |         scheduleLatestConfigRequest(); | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 282 |     } | 
 | 283 | } | 
 | 284 |  | 
| Alec Mouri | 33682e9 | 2020-01-10 15:11:15 -0800 | [diff] [blame] | 285 | void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, | 
 | 286 |                                                   void* data) { | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 287 |     std::lock_guard<std::mutex> _l{mLock}; | 
 | 288 |     mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(), | 
 | 289 |                                                mRefreshRateCallbacks.end(), | 
 | 290 |                                                [&](const RefreshRateCallback& callback) { | 
 | 291 |                                                    return cb == callback.callback && | 
 | 292 |                                                            data == callback.data; | 
 | 293 |                                                }), | 
 | 294 |                                 mRefreshRateCallbacks.end()); | 
 | 295 | } | 
 | 296 |  | 
 | 297 | void Choreographer::scheduleLatestConfigRequest() { | 
 | 298 |     if (mLooper != nullptr) { | 
 | 299 |         Message m{MSG_HANDLE_REFRESH_RATE_UPDATES}; | 
 | 300 |         mLooper->sendMessage(this, m); | 
 | 301 |     } else { | 
 | 302 |         // If the looper thread is detached from Choreographer, then refresh rate | 
 | 303 |         // changes will be handled in AChoreographer_handlePendingEvents, so we | 
| Alec Mouri | 967d5d7 | 2020-08-05 12:50:03 -0700 | [diff] [blame] | 304 |         // need to wake up the looper thread by writing to the write-end of the | 
 | 305 |         // socket the looper is listening on. | 
 | 306 |         // Fortunately, these events are small so sending packets across the | 
 | 307 |         // socket should be atomic across processes. | 
 | 308 |         DisplayEventReceiver::Event event; | 
 | 309 |         event.header = DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL, | 
 | 310 |                                                            PhysicalDisplayId(0), systemTime()}; | 
 | 311 |         injectEvent(event); | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 312 |     } | 
 | 313 | } | 
 | 314 |  | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 315 | void Choreographer::scheduleCallbacks() { | 
| Alec Mouri | 134266b | 2020-03-03 19:22:29 -0800 | [diff] [blame] | 316 |     const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); | 
 | 317 |     nsecs_t dueTime; | 
 | 318 |     { | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 319 |         std::lock_guard<std::mutex> _l{mLock}; | 
| Alec Mouri | 134266b | 2020-03-03 19:22:29 -0800 | [diff] [blame] | 320 |         // If there are no pending callbacks then don't schedule a vsync | 
 | 321 |         if (mFrameCallbacks.empty()) { | 
 | 322 |             return; | 
 | 323 |         } | 
 | 324 |         dueTime = mFrameCallbacks.top().dueTime; | 
 | 325 |     } | 
 | 326 |  | 
 | 327 |     if (dueTime <= now) { | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 328 |         ALOGV("choreographer %p ~ scheduling vsync", this); | 
 | 329 |         scheduleVsync(); | 
 | 330 |         return; | 
 | 331 |     } | 
 | 332 | } | 
 | 333 |  | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 334 | void Choreographer::handleRefreshRateUpdates() { | 
 | 335 |     std::vector<RefreshRateCallback> callbacks{}; | 
 | 336 |     const nsecs_t pendingPeriod = gChoreographers.mLastKnownVsync.load(); | 
 | 337 |     const nsecs_t lastPeriod = mLatestVsyncPeriod; | 
 | 338 |     if (pendingPeriod > 0) { | 
 | 339 |         mLatestVsyncPeriod = pendingPeriod; | 
 | 340 |     } | 
 | 341 |     { | 
 | 342 |         std::lock_guard<std::mutex> _l{mLock}; | 
 | 343 |         for (auto& cb : mRefreshRateCallbacks) { | 
 | 344 |             callbacks.push_back(cb); | 
 | 345 |             cb.firstCallbackFired = true; | 
 | 346 |         } | 
 | 347 |     } | 
 | 348 |  | 
 | 349 |     for (auto& cb : callbacks) { | 
 | 350 |         if (!cb.firstCallbackFired || (pendingPeriod > 0 && pendingPeriod != lastPeriod)) { | 
 | 351 |             cb.callback(pendingPeriod, cb.data); | 
 | 352 |         } | 
 | 353 |     } | 
 | 354 | } | 
 | 355 |  | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 356 | // TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the | 
 | 357 | // internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for | 
 | 358 | // the internal display implicitly. | 
| Ady Abraham | 0d28d76 | 2020-10-05 17:50:41 -0700 | [diff] [blame] | 359 | void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t, | 
 | 360 |                                   VsyncEventData vsyncEventData) { | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 361 |     std::vector<FrameCallback> callbacks{}; | 
 | 362 |     { | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 363 |         std::lock_guard<std::mutex> _l{mLock}; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 364 |         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 365 |         while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) { | 
 | 366 |             callbacks.push_back(mFrameCallbacks.top()); | 
 | 367 |             mFrameCallbacks.pop(); | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 368 |         } | 
 | 369 |     } | 
| Ady Abraham | 0d28d76 | 2020-10-05 17:50:41 -0700 | [diff] [blame] | 370 |     mLastVsyncEventData = vsyncEventData; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 371 |     for (const auto& cb : callbacks) { | 
 | 372 |         if (cb.callback64 != nullptr) { | 
 | 373 |             cb.callback64(timestamp, cb.data); | 
 | 374 |         } else if (cb.callback != nullptr) { | 
 | 375 |             cb.callback(timestamp, cb.data); | 
 | 376 |         } | 
 | 377 |     } | 
 | 378 | } | 
 | 379 |  | 
 | 380 | void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) { | 
| Marin Shalamanov | a524a09 | 2020-07-27 21:39:55 +0200 | [diff] [blame] | 381 |     ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.", | 
 | 382 |             this, to_string(displayId).c_str(), toString(connected)); | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 383 | } | 
 | 384 |  | 
| Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 385 | void Choreographer::dispatchModeChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) { | 
 | 386 |     LOG_ALWAYS_FATAL("dispatchModeChanged was called but was never registered"); | 
| Ady Abraham | 62f216c | 2020-10-13 19:07:23 -0700 | [diff] [blame] | 387 | } | 
 | 388 |  | 
 | 389 | void Choreographer::dispatchFrameRateOverrides(nsecs_t, PhysicalDisplayId, | 
 | 390 |                                                std::vector<FrameRateOverride>) { | 
 | 391 |     LOG_ALWAYS_FATAL("dispatchFrameRateOverrides was called but was never registered"); | 
| Alec Mouri | 967d5d7 | 2020-08-05 12:50:03 -0700 | [diff] [blame] | 392 | } | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 393 |  | 
| Alec Mouri | 967d5d7 | 2020-08-05 12:50:03 -0700 | [diff] [blame] | 394 | void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) { | 
 | 395 |     ALOGV("choreographer %p ~ received null event.", this); | 
 | 396 |     handleRefreshRateUpdates(); | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 397 | } | 
 | 398 |  | 
 | 399 | void Choreographer::handleMessage(const Message& message) { | 
 | 400 |     switch (message.what) { | 
 | 401 |     case MSG_SCHEDULE_CALLBACKS: | 
 | 402 |         scheduleCallbacks(); | 
 | 403 |         break; | 
 | 404 |     case MSG_SCHEDULE_VSYNC: | 
 | 405 |         scheduleVsync(); | 
 | 406 |         break; | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 407 |     case MSG_HANDLE_REFRESH_RATE_UPDATES: | 
 | 408 |         handleRefreshRateUpdates(); | 
 | 409 |         break; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 410 |     } | 
 | 411 | } | 
 | 412 |  | 
| Ady Abraham | 74e1756 | 2020-08-24 18:18:19 -0700 | [diff] [blame] | 413 | int64_t Choreographer::getVsyncId() const { | 
| Ady Abraham | 0d28d76 | 2020-10-05 17:50:41 -0700 | [diff] [blame] | 414 |     return mLastVsyncEventData.id; | 
 | 415 | } | 
 | 416 |  | 
 | 417 | int64_t Choreographer::getFrameDeadline() const { | 
 | 418 |     return mLastVsyncEventData.deadlineTimestamp; | 
| Ady Abraham | 74e1756 | 2020-08-24 18:18:19 -0700 | [diff] [blame] | 419 | } | 
 | 420 |  | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 421 | } // namespace android | 
| Alec Mouri | 50a931d | 2019-11-19 16:23:59 -0800 | [diff] [blame] | 422 | using namespace android; | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 423 |  | 
 | 424 | static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) { | 
 | 425 |     return reinterpret_cast<Choreographer*>(choreographer); | 
 | 426 | } | 
 | 427 |  | 
| Ady Abraham | 74e1756 | 2020-08-24 18:18:19 -0700 | [diff] [blame] | 428 | static inline const Choreographer* AChoreographer_to_Choreographer( | 
 | 429 |         const AChoreographer* choreographer) { | 
 | 430 |     return reinterpret_cast<const Choreographer*>(choreographer); | 
 | 431 | } | 
 | 432 |  | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 433 | // Glue for private C api | 
 | 434 | namespace android { | 
 | 435 | void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) { | 
 | 436 |     std::lock_guard<std::mutex> _l(gChoreographers.lock); | 
 | 437 |     gChoreographers.mLastKnownVsync.store(vsyncPeriod); | 
 | 438 |     for (auto c : gChoreographers.ptrs) { | 
 | 439 |         c->scheduleLatestConfigRequest(); | 
 | 440 |     } | 
 | 441 | } | 
 | 442 |  | 
 | 443 | void AChoreographer_initJVM(JNIEnv* env) { | 
 | 444 |     env->GetJavaVM(&gJni.jvm); | 
 | 445 |     // Now we need to find the java classes. | 
 | 446 |     jclass dmgClass = env->FindClass("android/hardware/display/DisplayManagerGlobal"); | 
 | 447 |     gJni.displayManagerGlobal.clazz = static_cast<jclass>(env->NewGlobalRef(dmgClass)); | 
 | 448 |     gJni.displayManagerGlobal.getInstance = | 
 | 449 |             env->GetStaticMethodID(dmgClass, "getInstance", | 
 | 450 |                                    "()Landroid/hardware/display/DisplayManagerGlobal;"); | 
 | 451 |     gJni.displayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks = | 
 | 452 |             env->GetMethodID(dmgClass, "registerNativeChoreographerForRefreshRateCallbacks", "()V"); | 
 | 453 |     gJni.displayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks = | 
 | 454 |             env->GetMethodID(dmgClass, "unregisterNativeChoreographerForRefreshRateCallbacks", | 
 | 455 |                              "()V"); | 
 | 456 | } | 
 | 457 |  | 
 | 458 | AChoreographer* AChoreographer_routeGetInstance() { | 
 | 459 |     return AChoreographer_getInstance(); | 
 | 460 | } | 
 | 461 | void AChoreographer_routePostFrameCallback(AChoreographer* choreographer, | 
 | 462 |                                            AChoreographer_frameCallback callback, void* data) { | 
| Jiyong Park | 8cdf076 | 2020-08-13 20:21:57 +0900 | [diff] [blame] | 463 | #pragma clang diagnostic push | 
 | 464 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 465 |     return AChoreographer_postFrameCallback(choreographer, callback, data); | 
| Jiyong Park | 8cdf076 | 2020-08-13 20:21:57 +0900 | [diff] [blame] | 466 | #pragma clang diagnostic pop | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 467 | } | 
 | 468 | void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer, | 
 | 469 |                                                   AChoreographer_frameCallback callback, void* data, | 
 | 470 |                                                   long delayMillis) { | 
| Jiyong Park | 8cdf076 | 2020-08-13 20:21:57 +0900 | [diff] [blame] | 471 | #pragma clang diagnostic push | 
 | 472 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 473 |     return AChoreographer_postFrameCallbackDelayed(choreographer, callback, data, delayMillis); | 
| Jiyong Park | 8cdf076 | 2020-08-13 20:21:57 +0900 | [diff] [blame] | 474 | #pragma clang diagnostic pop | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 475 | } | 
 | 476 | void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer, | 
 | 477 |                                              AChoreographer_frameCallback64 callback, void* data) { | 
 | 478 |     return AChoreographer_postFrameCallback64(choreographer, callback, data); | 
 | 479 | } | 
 | 480 | void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer, | 
 | 481 |                                                     AChoreographer_frameCallback64 callback, | 
 | 482 |                                                     void* data, uint32_t delayMillis) { | 
 | 483 |     return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis); | 
 | 484 | } | 
 | 485 | void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer, | 
 | 486 |                                                      AChoreographer_refreshRateCallback callback, | 
 | 487 |                                                      void* data) { | 
 | 488 |     return AChoreographer_registerRefreshRateCallback(choreographer, callback, data); | 
 | 489 | } | 
 | 490 | void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer, | 
 | 491 |                                                        AChoreographer_refreshRateCallback callback, | 
 | 492 |                                                        void* data) { | 
 | 493 |     return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data); | 
 | 494 | } | 
 | 495 |  | 
| Ady Abraham | 74e1756 | 2020-08-24 18:18:19 -0700 | [diff] [blame] | 496 | int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer) { | 
 | 497 |     return AChoreographer_to_Choreographer(choreographer)->getVsyncId(); | 
 | 498 | } | 
 | 499 |  | 
| Ady Abraham | 0d28d76 | 2020-10-05 17:50:41 -0700 | [diff] [blame] | 500 | int64_t AChoreographer_getFrameDeadline(const AChoreographer* choreographer) { | 
 | 501 |     return AChoreographer_to_Choreographer(choreographer)->getFrameDeadline(); | 
 | 502 | } | 
 | 503 |  | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 504 | } // namespace android | 
 | 505 |  | 
 | 506 | /* Glue for the NDK interface */ | 
 | 507 |  | 
| Alec Mouri | cc44522 | 2019-10-22 10:19:17 -0700 | [diff] [blame] | 508 | static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) { | 
 | 509 |     return reinterpret_cast<AChoreographer*>(choreographer); | 
 | 510 | } | 
 | 511 |  | 
 | 512 | AChoreographer* AChoreographer_getInstance() { | 
 | 513 |     return Choreographer_to_AChoreographer(Choreographer::getForThread()); | 
 | 514 | } | 
 | 515 |  | 
 | 516 | void AChoreographer_postFrameCallback(AChoreographer* choreographer, | 
 | 517 |         AChoreographer_frameCallback callback, void* data) { | 
 | 518 |     AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( | 
 | 519 |             callback, nullptr, data, 0); | 
 | 520 | } | 
 | 521 | void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, | 
 | 522 |         AChoreographer_frameCallback callback, void* data, long delayMillis) { | 
 | 523 |     AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( | 
 | 524 |             callback, nullptr, data, ms2ns(delayMillis)); | 
 | 525 | } | 
 | 526 | void AChoreographer_postFrameCallback64(AChoreographer* choreographer, | 
 | 527 |         AChoreographer_frameCallback64 callback, void* data) { | 
 | 528 |     AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( | 
 | 529 |             nullptr, callback, data, 0); | 
 | 530 | } | 
 | 531 | void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, | 
 | 532 |         AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) { | 
 | 533 |     AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( | 
 | 534 |             nullptr, callback, data, ms2ns(delayMillis)); | 
 | 535 | } | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 536 | void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer, | 
 | 537 |                                                 AChoreographer_refreshRateCallback callback, | 
 | 538 |                                                 void* data) { | 
 | 539 |     AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data); | 
 | 540 | } | 
 | 541 | void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, | 
| Alec Mouri | 33682e9 | 2020-01-10 15:11:15 -0800 | [diff] [blame] | 542 |                                                   AChoreographer_refreshRateCallback callback, | 
 | 543 |                                                   void* data) { | 
 | 544 |     AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback, data); | 
| Alec Mouri | 60aee1c | 2019-10-28 16:18:59 -0700 | [diff] [blame] | 545 | } | 
| Alec Mouri | 50a931d | 2019-11-19 16:23:59 -0800 | [diff] [blame] | 546 |  | 
 | 547 | AChoreographer* AChoreographer_create() { | 
 | 548 |     Choreographer* choreographer = new Choreographer(nullptr); | 
 | 549 |     status_t result = choreographer->initialize(); | 
 | 550 |     if (result != OK) { | 
 | 551 |         ALOGW("Failed to initialize"); | 
 | 552 |         return nullptr; | 
 | 553 |     } | 
 | 554 |     return Choreographer_to_AChoreographer(choreographer); | 
 | 555 | } | 
 | 556 |  | 
 | 557 | void AChoreographer_destroy(AChoreographer* choreographer) { | 
 | 558 |     if (choreographer == nullptr) { | 
 | 559 |         return; | 
 | 560 |     } | 
 | 561 |  | 
 | 562 |     delete AChoreographer_to_Choreographer(choreographer); | 
 | 563 | } | 
 | 564 |  | 
| Alec Mouri | 921b277 | 2020-02-05 19:03:28 -0800 | [diff] [blame] | 565 | int AChoreographer_getFd(const AChoreographer* choreographer) { | 
| Alec Mouri | 50a931d | 2019-11-19 16:23:59 -0800 | [diff] [blame] | 566 |     return AChoreographer_to_Choreographer(choreographer)->getFd(); | 
 | 567 | } | 
 | 568 |  | 
 | 569 | void AChoreographer_handlePendingEvents(AChoreographer* choreographer, void* data) { | 
 | 570 |     // Pass dummy fd and events args to handleEvent, since the underlying | 
 | 571 |     // DisplayEventDispatcher doesn't need them outside of validating that a | 
 | 572 |     // Looper instance didn't break, but these args circumvent those checks. | 
| Alec Mouri | 271de04 | 2020-04-27 22:38:19 -0700 | [diff] [blame] | 573 |     Choreographer* impl = AChoreographer_to_Choreographer(choreographer); | 
 | 574 |     impl->handleEvent(-1, Looper::EVENT_INPUT, data); | 
| Alec Mouri | 50a931d | 2019-11-19 16:23:59 -0800 | [diff] [blame] | 575 | } |