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