1 /* 2 * Copyright (C) 2011 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 ATRACE_TAG ATRACE_TAG_GRAPHICS 18 19 #include <pthread.h> 20 #include <sched.h> 21 #include <sys/types.h> 22 23 #include <chrono> 24 #include <cstdint> 25 #include <optional> 26 #include <type_traits> 27 28 #include <android-base/stringprintf.h> 29 30 #include <cutils/compiler.h> 31 #include <cutils/sched_policy.h> 32 33 #include <gui/DisplayEventReceiver.h> 34 35 #include <utils/Errors.h> 36 #include <utils/Trace.h> 37 38 #include "EventThread.h" 39 40 using namespace std::chrono_literals; 41 42 namespace android { 43 44 using base::StringAppendF; 45 using base::StringPrintf; 46 47 namespace { 48 49 auto vsyncPeriod(VSyncRequest request) { 50 return static_cast<std::underlying_type_t<VSyncRequest>>(request); 51 } 52 53 std::string toString(VSyncRequest request) { 54 switch (request) { 55 case VSyncRequest::None: 56 return "VSyncRequest::None"; 57 case VSyncRequest::Single: 58 return "VSyncRequest::Single"; 59 default: 60 return StringPrintf("VSyncRequest::Periodic{period=%d}", vsyncPeriod(request)); 61 } 62 } 63 64 std::string toString(const EventThreadConnection& connection) { 65 return StringPrintf("Connection{%p, %s}", &connection, 66 toString(connection.vsyncRequest).c_str()); 67 } 68 69 std::string toString(const DisplayEventReceiver::Event& event) { 70 switch (event.header.type) { 71 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: 72 return StringPrintf("Hotplug{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", %s}", 73 event.header.displayId, 74 event.hotplug.connected ? "connected" : "disconnected"); 75 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: 76 return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT 77 ", count=%u}", 78 event.header.displayId, event.vsync.count); 79 default: 80 return "Event{}"; 81 } 82 } 83 84 DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t timestamp, 85 bool connected) { 86 DisplayEventReceiver::Event event; 87 event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, displayId, timestamp}; 88 event.hotplug.connected = connected; 89 return event; 90 } 91 92 DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp, 93 uint32_t count) { 94 DisplayEventReceiver::Event event; 95 event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp}; 96 event.vsync.count = count; 97 return event; 98 } 99 100 DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, int32_t configId) { 101 DisplayEventReceiver::Event event; 102 event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()}; 103 event.config.configId = configId; 104 return event; 105 } 106 107 } // namespace 108 109 EventThreadConnection::EventThreadConnection(EventThread* eventThread, 110 ResyncCallback resyncCallback) 111 : resyncCallback(std::move(resyncCallback)), 112 mEventThread(eventThread), 113 mChannel(gui::BitTube::DefaultSize) {} 114 115 EventThreadConnection::~EventThreadConnection() { 116 // do nothing here -- clean-up will happen automatically 117 // when the main thread wakes up 118 } 119 120 void EventThreadConnection::onFirstRef() { 121 // NOTE: mEventThread doesn't hold a strong reference on us 122 mEventThread->registerDisplayEventConnection(this); 123 } 124 125 status_t EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) { 126 outChannel->setReceiveFd(mChannel.moveReceiveFd()); 127 return NO_ERROR; 128 } 129 130 status_t EventThreadConnection::setVsyncRate(uint32_t rate) { 131 mEventThread->setVsyncRate(rate, this); 132 return NO_ERROR; 133 } 134 135 void EventThreadConnection::requestNextVsync() { 136 ATRACE_NAME("requestNextVsync"); 137 mEventThread->requestNextVsync(this); 138 } 139 140 status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) { 141 ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1); 142 return size < 0 ? status_t(size) : status_t(NO_ERROR); 143 } 144 145 // --------------------------------------------------------------------------- 146 147 EventThread::~EventThread() = default; 148 149 namespace impl { 150 151 EventThread::EventThread(std::unique_ptr<VSyncSource> src, 152 InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName) 153 : EventThread(nullptr, std::move(src), std::move(interceptVSyncsCallback), threadName) {} 154 155 EventThread::EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback, 156 const char* threadName) 157 : EventThread(src, nullptr, std::move(interceptVSyncsCallback), threadName) {} 158 159 EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc, 160 InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName) 161 : mVSyncSource(src), 162 mVSyncSourceUnique(std::move(uniqueSrc)), 163 mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)), 164 mThreadName(threadName) { 165 if (src == nullptr) { 166 mVSyncSource = mVSyncSourceUnique.get(); 167 } 168 mVSyncSource->setCallback(this); 169 170 mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS { 171 std::unique_lock<std::mutex> lock(mMutex); 172 threadMain(lock); 173 }); 174 175 pthread_setname_np(mThread.native_handle(), threadName); 176 177 pid_t tid = pthread_gettid_np(mThread.native_handle()); 178 179 // Use SCHED_FIFO to minimize jitter 180 constexpr int EVENT_THREAD_PRIORITY = 2; 181 struct sched_param param = {0}; 182 param.sched_priority = EVENT_THREAD_PRIORITY; 183 if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, ¶m) != 0) { 184 ALOGE("Couldn't set SCHED_FIFO for EventThread"); 185 } 186 187 set_sched_policy(tid, SP_FOREGROUND); 188 } 189 190 EventThread::~EventThread() { 191 mVSyncSource->setCallback(nullptr); 192 193 { 194 std::lock_guard<std::mutex> lock(mMutex); 195 mState = State::Quit; 196 mCondition.notify_all(); 197 } 198 mThread.join(); 199 } 200 201 void EventThread::setPhaseOffset(nsecs_t phaseOffset) { 202 std::lock_guard<std::mutex> lock(mMutex); 203 mVSyncSource->setPhaseOffset(phaseOffset); 204 } 205 206 sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const { 207 return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback)); 208 } 209 210 status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) { 211 std::lock_guard<std::mutex> lock(mMutex); 212 213 // this should never happen 214 auto it = std::find(mDisplayEventConnections.cbegin(), 215 mDisplayEventConnections.cend(), connection); 216 if (it != mDisplayEventConnections.cend()) { 217 ALOGW("DisplayEventConnection %p already exists", connection.get()); 218 mCondition.notify_all(); 219 return ALREADY_EXISTS; 220 } 221 222 mDisplayEventConnections.push_back(connection); 223 mCondition.notify_all(); 224 return NO_ERROR; 225 } 226 227 void EventThread::removeDisplayEventConnectionLocked(const wp<EventThreadConnection>& connection) { 228 auto it = std::find(mDisplayEventConnections.cbegin(), 229 mDisplayEventConnections.cend(), connection); 230 if (it != mDisplayEventConnections.cend()) { 231 mDisplayEventConnections.erase(it); 232 } 233 } 234 235 void EventThread::setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) { 236 if (static_cast<std::underlying_type_t<VSyncRequest>>(rate) < 0) { 237 return; 238 } 239 240 std::lock_guard<std::mutex> lock(mMutex); 241 242 const auto request = rate == 0 ? VSyncRequest::None : static_cast<VSyncRequest>(rate); 243 if (connection->vsyncRequest != request) { 244 connection->vsyncRequest = request; 245 mCondition.notify_all(); 246 } 247 } 248 249 void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) { 250 if (connection->resyncCallback) { 251 connection->resyncCallback(); 252 } 253 254 std::lock_guard<std::mutex> lock(mMutex); 255 256 if (connection->vsyncRequest == VSyncRequest::None) { 257 connection->vsyncRequest = VSyncRequest::Single; 258 mCondition.notify_all(); 259 } 260 } 261 262 void EventThread::onScreenReleased() { 263 std::lock_guard<std::mutex> lock(mMutex); 264 if (!mVSyncState || mVSyncState->synthetic) { 265 return; 266 } 267 268 mVSyncState->synthetic = true; 269 mCondition.notify_all(); 270 } 271 272 void EventThread::onScreenAcquired() { 273 std::lock_guard<std::mutex> lock(mMutex); 274 if (!mVSyncState || !mVSyncState->synthetic) { 275 return; 276 } 277 278 mVSyncState->synthetic = false; 279 mCondition.notify_all(); 280 } 281 282 void EventThread::onVSyncEvent(nsecs_t timestamp) { 283 std::lock_guard<std::mutex> lock(mMutex); 284 285 LOG_FATAL_IF(!mVSyncState); 286 mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count)); 287 mCondition.notify_all(); 288 } 289 290 void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) { 291 std::lock_guard<std::mutex> lock(mMutex); 292 293 mPendingEvents.push_back(makeHotplug(displayId, systemTime(), connected)); 294 mCondition.notify_all(); 295 } 296 297 void EventThread::onConfigChanged(PhysicalDisplayId displayId, int32_t configId) { 298 std::lock_guard<std::mutex> lock(mMutex); 299 300 mPendingEvents.push_back(makeConfigChanged(displayId, configId)); 301 mCondition.notify_all(); 302 } 303 304 void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { 305 DisplayEventConsumers consumers; 306 307 while (mState != State::Quit) { 308 std::optional<DisplayEventReceiver::Event> event; 309 310 // Determine next event to dispatch. 311 if (!mPendingEvents.empty()) { 312 event = mPendingEvents.front(); 313 mPendingEvents.pop_front(); 314 315 switch (event->header.type) { 316 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: 317 if (event->hotplug.connected && !mVSyncState) { 318 mVSyncState.emplace(event->header.displayId); 319 } else if (!event->hotplug.connected && mVSyncState && 320 mVSyncState->displayId == event->header.displayId) { 321 mVSyncState.reset(); 322 } 323 break; 324 325 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: 326 if (mInterceptVSyncsCallback) { 327 mInterceptVSyncsCallback(event->header.timestamp); 328 } 329 break; 330 } 331 } 332 333 bool vsyncRequested = false; 334 335 // Find connections that should consume this event. 336 auto it = mDisplayEventConnections.begin(); 337 while (it != mDisplayEventConnections.end()) { 338 if (const auto connection = it->promote()) { 339 vsyncRequested |= connection->vsyncRequest != VSyncRequest::None; 340 341 if (event && shouldConsumeEvent(*event, connection)) { 342 consumers.push_back(connection); 343 } 344 345 ++it; 346 } else { 347 it = mDisplayEventConnections.erase(it); 348 } 349 } 350 351 if (!consumers.empty()) { 352 dispatchEvent(*event, consumers); 353 consumers.clear(); 354 } 355 356 State nextState; 357 if (mVSyncState && vsyncRequested) { 358 nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync; 359 } else { 360 ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected"); 361 nextState = State::Idle; 362 } 363 364 if (mState != nextState) { 365 if (mState == State::VSync) { 366 mVSyncSource->setVSyncEnabled(false); 367 } else if (nextState == State::VSync) { 368 mVSyncSource->setVSyncEnabled(true); 369 } 370 371 mState = nextState; 372 } 373 374 if (event) { 375 continue; 376 } 377 378 // Wait for event or client registration/request. 379 if (mState == State::Idle) { 380 mCondition.wait(lock); 381 } else { 382 // Generate a fake VSYNC after a long timeout in case the driver stalls. When the 383 // display is off, keep feeding clients at 60 Hz. 384 const auto timeout = mState == State::SyntheticVSync ? 16ms : 1000ms; 385 if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) { 386 ALOGW_IF(mState == State::VSync, "Faking VSYNC due to driver stall"); 387 388 LOG_FATAL_IF(!mVSyncState); 389 mPendingEvents.push_back(makeVSync(mVSyncState->displayId, 390 systemTime(SYSTEM_TIME_MONOTONIC), 391 ++mVSyncState->count)); 392 } 393 } 394 } 395 } 396 397 bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, 398 const sp<EventThreadConnection>& connection) const { 399 switch (event.header.type) { 400 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: 401 case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: 402 return true; 403 404 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: 405 switch (connection->vsyncRequest) { 406 case VSyncRequest::None: 407 return false; 408 case VSyncRequest::Single: 409 connection->vsyncRequest = VSyncRequest::None; 410 return true; 411 case VSyncRequest::Periodic: 412 return true; 413 default: 414 return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0; 415 } 416 417 default: 418 return false; 419 } 420 } 421 422 void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, 423 const DisplayEventConsumers& consumers) { 424 for (const auto& consumer : consumers) { 425 switch (consumer->postEvent(event)) { 426 case NO_ERROR: 427 break; 428 429 case -EAGAIN: 430 // TODO: Try again if pipe is full. 431 ALOGW("Failed dispatching %s for %s", toString(event).c_str(), 432 toString(*consumer).c_str()); 433 break; 434 435 default: 436 // Treat EPIPE and other errors as fatal. 437 removeDisplayEventConnectionLocked(consumer); 438 } 439 } 440 } 441 442 void EventThread::dump(std::string& result) const { 443 std::lock_guard<std::mutex> lock(mMutex); 444 445 StringAppendF(&result, "%s: state=%s VSyncState=", mThreadName, toCString(mState)); 446 if (mVSyncState) { 447 StringAppendF(&result, "{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%u%s}\n", 448 mVSyncState->displayId, mVSyncState->count, 449 mVSyncState->synthetic ? ", synthetic" : ""); 450 } else { 451 StringAppendF(&result, "none\n"); 452 } 453 454 StringAppendF(&result, " pending events (count=%zu):\n", mPendingEvents.size()); 455 for (const auto& event : mPendingEvents) { 456 StringAppendF(&result, " %s\n", toString(event).c_str()); 457 } 458 459 StringAppendF(&result, " connections (count=%zu):\n", mDisplayEventConnections.size()); 460 for (const auto& ptr : mDisplayEventConnections) { 461 if (const auto connection = ptr.promote()) { 462 StringAppendF(&result, " %s\n", toString(*connection).c_str()); 463 } 464 } 465 } 466 467 const char* EventThread::toCString(State state) { 468 switch (state) { 469 case State::Idle: 470 return "Idle"; 471 case State::Quit: 472 return "Quit"; 473 case State::SyntheticVSync: 474 return "SyntheticVSync"; 475 case State::VSync: 476 return "VSync"; 477 } 478 } 479 480 } // namespace impl 481 } // namespace android 482