• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd())));
143     return NO_ERROR;
144 }
145 
setVsyncRate(uint32_t rate)146 status_t EventThreadConnection::setVsyncRate(uint32_t rate) {
147     mEventThread->setVsyncRate(rate, this);
148     return NO_ERROR;
149 }
150 
requestNextVsync()151 void EventThreadConnection::requestNextVsync() {
152     ATRACE_NAME("requestNextVsync");
153     mEventThread->requestNextVsync(this);
154 }
155 
postEvent(const DisplayEventReceiver::Event & event)156 status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
157     ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
158     return size < 0 ? status_t(size) : status_t(NO_ERROR);
159 }
160 
161 // ---------------------------------------------------------------------------
162 
163 EventThread::~EventThread() = default;
164 
165 namespace impl {
166 
EventThread(std::unique_ptr<VSyncSource> vsyncSource,InterceptVSyncsCallback interceptVSyncsCallback)167 EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
168                          InterceptVSyncsCallback interceptVSyncsCallback)
169       : mVSyncSource(std::move(vsyncSource)),
170         mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
171         mThreadName(mVSyncSource->getName()) {
172     mVSyncSource->setCallback(this);
173 
174     mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
175         std::unique_lock<std::mutex> lock(mMutex);
176         threadMain(lock);
177     });
178 
179     pthread_setname_np(mThread.native_handle(), mThreadName);
180 
181     pid_t tid = pthread_gettid_np(mThread.native_handle());
182 
183     // Use SCHED_FIFO to minimize jitter
184     constexpr int EVENT_THREAD_PRIORITY = 2;
185     struct sched_param param = {0};
186     param.sched_priority = EVENT_THREAD_PRIORITY;
187     if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, &param) != 0) {
188         ALOGE("Couldn't set SCHED_FIFO for EventThread");
189     }
190 
191     set_sched_policy(tid, SP_FOREGROUND);
192 }
193 
~EventThread()194 EventThread::~EventThread() {
195     mVSyncSource->setCallback(nullptr);
196 
197     {
198         std::lock_guard<std::mutex> lock(mMutex);
199         mState = State::Quit;
200         mCondition.notify_all();
201     }
202     mThread.join();
203 }
204 
setPhaseOffset(nsecs_t phaseOffset)205 void EventThread::setPhaseOffset(nsecs_t phaseOffset) {
206     std::lock_guard<std::mutex> lock(mMutex);
207     mVSyncSource->setPhaseOffset(phaseOffset);
208 }
209 
createEventConnection(ResyncCallback resyncCallback,ISurfaceComposer::ConfigChanged configChanged) const210 sp<EventThreadConnection> EventThread::createEventConnection(
211         ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const {
212     return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
213                                      configChanged);
214 }
215 
registerDisplayEventConnection(const sp<EventThreadConnection> & connection)216 status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
217     std::lock_guard<std::mutex> lock(mMutex);
218 
219     // this should never happen
220     auto it = std::find(mDisplayEventConnections.cbegin(),
221             mDisplayEventConnections.cend(), connection);
222     if (it != mDisplayEventConnections.cend()) {
223         ALOGW("DisplayEventConnection %p already exists", connection.get());
224         mCondition.notify_all();
225         return ALREADY_EXISTS;
226     }
227 
228     mDisplayEventConnections.push_back(connection);
229     mCondition.notify_all();
230     return NO_ERROR;
231 }
232 
removeDisplayEventConnectionLocked(const wp<EventThreadConnection> & connection)233 void EventThread::removeDisplayEventConnectionLocked(const wp<EventThreadConnection>& connection) {
234     auto it = std::find(mDisplayEventConnections.cbegin(),
235             mDisplayEventConnections.cend(), connection);
236     if (it != mDisplayEventConnections.cend()) {
237         mDisplayEventConnections.erase(it);
238     }
239 }
240 
setVsyncRate(uint32_t rate,const sp<EventThreadConnection> & connection)241 void EventThread::setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) {
242     if (static_cast<std::underlying_type_t<VSyncRequest>>(rate) < 0) {
243         return;
244     }
245 
246     std::lock_guard<std::mutex> lock(mMutex);
247 
248     const auto request = rate == 0 ? VSyncRequest::None : static_cast<VSyncRequest>(rate);
249     if (connection->vsyncRequest != request) {
250         connection->vsyncRequest = request;
251         mCondition.notify_all();
252     }
253 }
254 
requestNextVsync(const sp<EventThreadConnection> & connection)255 void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
256     if (connection->resyncCallback) {
257         connection->resyncCallback();
258     }
259 
260     std::lock_guard<std::mutex> lock(mMutex);
261 
262     if (connection->vsyncRequest == VSyncRequest::None) {
263         connection->vsyncRequest = VSyncRequest::Single;
264         mCondition.notify_all();
265     }
266 }
267 
onScreenReleased()268 void EventThread::onScreenReleased() {
269     std::lock_guard<std::mutex> lock(mMutex);
270     if (!mVSyncState || mVSyncState->synthetic) {
271         return;
272     }
273 
274     mVSyncState->synthetic = true;
275     mCondition.notify_all();
276 }
277 
onScreenAcquired()278 void EventThread::onScreenAcquired() {
279     std::lock_guard<std::mutex> lock(mMutex);
280     if (!mVSyncState || !mVSyncState->synthetic) {
281         return;
282     }
283 
284     mVSyncState->synthetic = false;
285     mCondition.notify_all();
286 }
287 
onVSyncEvent(nsecs_t timestamp,nsecs_t expectedVSyncTimestamp)288 void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) {
289     std::lock_guard<std::mutex> lock(mMutex);
290 
291     LOG_FATAL_IF(!mVSyncState);
292     mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
293                                        expectedVSyncTimestamp));
294     mCondition.notify_all();
295 }
296 
onHotplugReceived(PhysicalDisplayId displayId,bool connected)297 void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) {
298     std::lock_guard<std::mutex> lock(mMutex);
299 
300     mPendingEvents.push_back(makeHotplug(displayId, systemTime(), connected));
301     mCondition.notify_all();
302 }
303 
onConfigChanged(PhysicalDisplayId displayId,HwcConfigIndexType configId,nsecs_t vsyncPeriod)304 void EventThread::onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
305                                   nsecs_t vsyncPeriod) {
306     std::lock_guard<std::mutex> lock(mMutex);
307 
308     mPendingEvents.push_back(makeConfigChanged(displayId, configId, vsyncPeriod));
309     mCondition.notify_all();
310 }
311 
getEventThreadConnectionCount()312 size_t EventThread::getEventThreadConnectionCount() {
313     std::lock_guard<std::mutex> lock(mMutex);
314     return mDisplayEventConnections.size();
315 }
316 
threadMain(std::unique_lock<std::mutex> & lock)317 void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
318     DisplayEventConsumers consumers;
319 
320     while (mState != State::Quit) {
321         std::optional<DisplayEventReceiver::Event> event;
322 
323         // Determine next event to dispatch.
324         if (!mPendingEvents.empty()) {
325             event = mPendingEvents.front();
326             mPendingEvents.pop_front();
327 
328             switch (event->header.type) {
329                 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
330                     if (event->hotplug.connected && !mVSyncState) {
331                         mVSyncState.emplace(event->header.displayId);
332                     } else if (!event->hotplug.connected && mVSyncState &&
333                                mVSyncState->displayId == event->header.displayId) {
334                         mVSyncState.reset();
335                     }
336                     break;
337 
338                 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
339                     if (mInterceptVSyncsCallback) {
340                         mInterceptVSyncsCallback(event->header.timestamp);
341                     }
342                     break;
343             }
344         }
345 
346         bool vsyncRequested = false;
347 
348         // Find connections that should consume this event.
349         auto it = mDisplayEventConnections.begin();
350         while (it != mDisplayEventConnections.end()) {
351             if (const auto connection = it->promote()) {
352                 vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
353 
354                 if (event && shouldConsumeEvent(*event, connection)) {
355                     consumers.push_back(connection);
356                 }
357 
358                 ++it;
359             } else {
360                 it = mDisplayEventConnections.erase(it);
361             }
362         }
363 
364         if (!consumers.empty()) {
365             dispatchEvent(*event, consumers);
366             consumers.clear();
367         }
368 
369         State nextState;
370         if (mVSyncState && vsyncRequested) {
371             nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
372         } else {
373             ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
374             nextState = State::Idle;
375         }
376 
377         if (mState != nextState) {
378             if (mState == State::VSync) {
379                 mVSyncSource->setVSyncEnabled(false);
380             } else if (nextState == State::VSync) {
381                 mVSyncSource->setVSyncEnabled(true);
382             }
383 
384             mState = nextState;
385         }
386 
387         if (event) {
388             continue;
389         }
390 
391         // Wait for event or client registration/request.
392         if (mState == State::Idle) {
393             mCondition.wait(lock);
394         } else {
395             // Generate a fake VSYNC after a long timeout in case the driver stalls. When the
396             // display is off, keep feeding clients at 60 Hz.
397             const std::chrono::nanoseconds timeout =
398                     mState == State::SyntheticVSync ? 16ms : 1000ms;
399             if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
400                 if (mState == State::VSync) {
401                     ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName);
402                     std::string debugInfo = "VsyncSource debug info:\n";
403                     mVSyncSource->dump(debugInfo);
404                     // Log the debug info line-by-line to avoid logcat overflow
405                     auto pos = debugInfo.find('\n');
406                     while (pos != std::string::npos) {
407                         ALOGW("%s", debugInfo.substr(0, pos).c_str());
408                         debugInfo = debugInfo.substr(pos + 1);
409                         pos = debugInfo.find('\n');
410                     }
411                 }
412 
413                 LOG_FATAL_IF(!mVSyncState);
414                 const auto now = systemTime(SYSTEM_TIME_MONOTONIC);
415                 const auto expectedVSyncTime = now + timeout.count();
416                 mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now,
417                                                    ++mVSyncState->count, expectedVSyncTime));
418             }
419         }
420     }
421 }
422 
shouldConsumeEvent(const DisplayEventReceiver::Event & event,const sp<EventThreadConnection> & connection) const423 bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
424                                      const sp<EventThreadConnection>& connection) const {
425     switch (event.header.type) {
426         case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
427             return true;
428 
429         case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: {
430             return connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
431         }
432 
433         case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
434             switch (connection->vsyncRequest) {
435                 case VSyncRequest::None:
436                     return false;
437                 case VSyncRequest::Single:
438                     connection->vsyncRequest = VSyncRequest::None;
439                     return true;
440                 case VSyncRequest::Periodic:
441                     return true;
442                 default:
443                     return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0;
444             }
445 
446         default:
447             return false;
448     }
449 }
450 
dispatchEvent(const DisplayEventReceiver::Event & event,const DisplayEventConsumers & consumers)451 void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
452                                 const DisplayEventConsumers& consumers) {
453     for (const auto& consumer : consumers) {
454         switch (consumer->postEvent(event)) {
455             case NO_ERROR:
456                 break;
457 
458             case -EAGAIN:
459                 // TODO: Try again if pipe is full.
460                 ALOGW("Failed dispatching %s for %s", toString(event).c_str(),
461                       toString(*consumer).c_str());
462                 break;
463 
464             default:
465                 // Treat EPIPE and other errors as fatal.
466                 removeDisplayEventConnectionLocked(consumer);
467         }
468     }
469 }
470 
dump(std::string & result) const471 void EventThread::dump(std::string& result) const {
472     std::lock_guard<std::mutex> lock(mMutex);
473 
474     StringAppendF(&result, "%s: state=%s VSyncState=", mThreadName, toCString(mState));
475     if (mVSyncState) {
476         StringAppendF(&result, "{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%u%s}\n",
477                       mVSyncState->displayId, mVSyncState->count,
478                       mVSyncState->synthetic ? ", synthetic" : "");
479     } else {
480         StringAppendF(&result, "none\n");
481     }
482 
483     StringAppendF(&result, "  pending events (count=%zu):\n", mPendingEvents.size());
484     for (const auto& event : mPendingEvents) {
485         StringAppendF(&result, "    %s\n", toString(event).c_str());
486     }
487 
488     StringAppendF(&result, "  connections (count=%zu):\n", mDisplayEventConnections.size());
489     for (const auto& ptr : mDisplayEventConnections) {
490         if (const auto connection = ptr.promote()) {
491             StringAppendF(&result, "    %s\n", toString(*connection).c_str());
492         }
493     }
494 }
495 
toCString(State state)496 const char* EventThread::toCString(State state) {
497     switch (state) {
498         case State::Idle:
499             return "Idle";
500         case State::Quit:
501             return "Quit";
502         case State::SyntheticVSync:
503             return "SyntheticVSync";
504         case State::VSync:
505             return "VSync";
506     }
507 }
508 
509 } // namespace impl
510 } // namespace android
511 
512 // TODO(b/129481165): remove the #pragma below and fix conversion issues
513 #pragma clang diagnostic pop // ignored "-Wconversion"
514