xref: /aosp_15_r20/frameworks/native/libs/gui/DisplayEventDispatcher.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "DisplayEventDispatcher"
18*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19*38e8c45fSAndroid Build Coastguard Worker 
20*38e8c45fSAndroid Build Coastguard Worker #include <cinttypes>
21*38e8c45fSAndroid Build Coastguard Worker #include <cstdint>
22*38e8c45fSAndroid Build Coastguard Worker 
23*38e8c45fSAndroid Build Coastguard Worker #include <gui/DisplayEventDispatcher.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <gui/DisplayEventReceiver.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <utils/Log.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <utils/Looper.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <utils/Trace.h>
29*38e8c45fSAndroid Build Coastguard Worker 
30*38e8c45fSAndroid Build Coastguard Worker #include <com_android_graphics_libgui_flags.h>
31*38e8c45fSAndroid Build Coastguard Worker 
32*38e8c45fSAndroid Build Coastguard Worker namespace android {
33*38e8c45fSAndroid Build Coastguard Worker using namespace com::android::graphics::libgui;
34*38e8c45fSAndroid Build Coastguard Worker 
35*38e8c45fSAndroid Build Coastguard Worker // Number of events to read at a time from the DisplayEventDispatcher pipe.
36*38e8c45fSAndroid Build Coastguard Worker // The value should be large enough that we can quickly drain the pipe
37*38e8c45fSAndroid Build Coastguard Worker // using just a few large reads.
38*38e8c45fSAndroid Build Coastguard Worker static const size_t EVENT_BUFFER_SIZE = 100;
39*38e8c45fSAndroid Build Coastguard Worker 
40*38e8c45fSAndroid Build Coastguard Worker static constexpr nsecs_t WAITING_FOR_VSYNC_TIMEOUT = ms2ns(300);
41*38e8c45fSAndroid Build Coastguard Worker 
DisplayEventDispatcher(const sp<Looper> & looper,gui::ISurfaceComposer::VsyncSource vsyncSource,EventRegistrationFlags eventRegistration,const sp<IBinder> & layerHandle)42*38e8c45fSAndroid Build Coastguard Worker DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
43*38e8c45fSAndroid Build Coastguard Worker                                                gui::ISurfaceComposer::VsyncSource vsyncSource,
44*38e8c45fSAndroid Build Coastguard Worker                                                EventRegistrationFlags eventRegistration,
45*38e8c45fSAndroid Build Coastguard Worker                                                const sp<IBinder>& layerHandle)
46*38e8c45fSAndroid Build Coastguard Worker       : mLooper(looper),
47*38e8c45fSAndroid Build Coastguard Worker         mReceiver(vsyncSource, eventRegistration, layerHandle),
48*38e8c45fSAndroid Build Coastguard Worker         mWaitingForVsync(false),
49*38e8c45fSAndroid Build Coastguard Worker         mLastVsyncCount(0),
50*38e8c45fSAndroid Build Coastguard Worker         mLastScheduleVsyncTime(0) {
51*38e8c45fSAndroid Build Coastguard Worker     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
52*38e8c45fSAndroid Build Coastguard Worker }
53*38e8c45fSAndroid Build Coastguard Worker 
initialize()54*38e8c45fSAndroid Build Coastguard Worker status_t DisplayEventDispatcher::initialize() {
55*38e8c45fSAndroid Build Coastguard Worker     status_t result = mReceiver.initCheck();
56*38e8c45fSAndroid Build Coastguard Worker     if (result) {
57*38e8c45fSAndroid Build Coastguard Worker         ALOGW("Failed to initialize display event receiver, status=%d", result);
58*38e8c45fSAndroid Build Coastguard Worker         return result;
59*38e8c45fSAndroid Build Coastguard Worker     }
60*38e8c45fSAndroid Build Coastguard Worker 
61*38e8c45fSAndroid Build Coastguard Worker     if (mLooper != nullptr) {
62*38e8c45fSAndroid Build Coastguard Worker         int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
63*38e8c45fSAndroid Build Coastguard Worker         if (rc < 0) {
64*38e8c45fSAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
65*38e8c45fSAndroid Build Coastguard Worker         }
66*38e8c45fSAndroid Build Coastguard Worker     }
67*38e8c45fSAndroid Build Coastguard Worker 
68*38e8c45fSAndroid Build Coastguard Worker     return OK;
69*38e8c45fSAndroid Build Coastguard Worker }
70*38e8c45fSAndroid Build Coastguard Worker 
dispose()71*38e8c45fSAndroid Build Coastguard Worker void DisplayEventDispatcher::dispose() {
72*38e8c45fSAndroid Build Coastguard Worker     ALOGV("dispatcher %p ~ Disposing display event dispatcher.", this);
73*38e8c45fSAndroid Build Coastguard Worker 
74*38e8c45fSAndroid Build Coastguard Worker     if (!mReceiver.initCheck() && mLooper != nullptr) {
75*38e8c45fSAndroid Build Coastguard Worker         mLooper->removeFd(mReceiver.getFd());
76*38e8c45fSAndroid Build Coastguard Worker     }
77*38e8c45fSAndroid Build Coastguard Worker }
78*38e8c45fSAndroid Build Coastguard Worker 
scheduleVsync()79*38e8c45fSAndroid Build Coastguard Worker status_t DisplayEventDispatcher::scheduleVsync() {
80*38e8c45fSAndroid Build Coastguard Worker     if (!mWaitingForVsync) {
81*38e8c45fSAndroid Build Coastguard Worker         ALOGV("dispatcher %p ~ Scheduling vsync.", this);
82*38e8c45fSAndroid Build Coastguard Worker 
83*38e8c45fSAndroid Build Coastguard Worker         // Drain all pending events.
84*38e8c45fSAndroid Build Coastguard Worker         nsecs_t vsyncTimestamp;
85*38e8c45fSAndroid Build Coastguard Worker         PhysicalDisplayId vsyncDisplayId;
86*38e8c45fSAndroid Build Coastguard Worker         uint32_t vsyncCount;
87*38e8c45fSAndroid Build Coastguard Worker         VsyncEventData vsyncEventData;
88*38e8c45fSAndroid Build Coastguard Worker         if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
89*38e8c45fSAndroid Build Coastguard Worker             ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
90*38e8c45fSAndroid Build Coastguard Worker                   ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
91*38e8c45fSAndroid Build Coastguard Worker         }
92*38e8c45fSAndroid Build Coastguard Worker 
93*38e8c45fSAndroid Build Coastguard Worker         status_t status = mReceiver.requestNextVsync();
94*38e8c45fSAndroid Build Coastguard Worker         if (status) {
95*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Failed to request next vsync, status=%d", status);
96*38e8c45fSAndroid Build Coastguard Worker             return status;
97*38e8c45fSAndroid Build Coastguard Worker         }
98*38e8c45fSAndroid Build Coastguard Worker 
99*38e8c45fSAndroid Build Coastguard Worker         mWaitingForVsync = true;
100*38e8c45fSAndroid Build Coastguard Worker         mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC);
101*38e8c45fSAndroid Build Coastguard Worker     }
102*38e8c45fSAndroid Build Coastguard Worker     return OK;
103*38e8c45fSAndroid Build Coastguard Worker }
104*38e8c45fSAndroid Build Coastguard Worker 
injectEvent(const DisplayEventReceiver::Event & event)105*38e8c45fSAndroid Build Coastguard Worker void DisplayEventDispatcher::injectEvent(const DisplayEventReceiver::Event& event) {
106*38e8c45fSAndroid Build Coastguard Worker     mReceiver.sendEvents(&event, 1);
107*38e8c45fSAndroid Build Coastguard Worker }
108*38e8c45fSAndroid Build Coastguard Worker 
getFd() const109*38e8c45fSAndroid Build Coastguard Worker int DisplayEventDispatcher::getFd() const {
110*38e8c45fSAndroid Build Coastguard Worker     return mReceiver.getFd();
111*38e8c45fSAndroid Build Coastguard Worker }
112*38e8c45fSAndroid Build Coastguard Worker 
handleEvent(int,int events,void *)113*38e8c45fSAndroid Build Coastguard Worker int DisplayEventDispatcher::handleEvent(int, int events, void*) {
114*38e8c45fSAndroid Build Coastguard Worker     if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
115*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Display event receiver pipe was closed or an error occurred.  "
116*38e8c45fSAndroid Build Coastguard Worker               "events=0x%x",
117*38e8c45fSAndroid Build Coastguard Worker               events);
118*38e8c45fSAndroid Build Coastguard Worker         return 0; // remove the callback
119*38e8c45fSAndroid Build Coastguard Worker     }
120*38e8c45fSAndroid Build Coastguard Worker 
121*38e8c45fSAndroid Build Coastguard Worker     if (!(events & Looper::EVENT_INPUT)) {
122*38e8c45fSAndroid Build Coastguard Worker         ALOGW("Received spurious callback for unhandled poll event.  "
123*38e8c45fSAndroid Build Coastguard Worker               "events=0x%x",
124*38e8c45fSAndroid Build Coastguard Worker               events);
125*38e8c45fSAndroid Build Coastguard Worker         return 1; // keep the callback
126*38e8c45fSAndroid Build Coastguard Worker     }
127*38e8c45fSAndroid Build Coastguard Worker 
128*38e8c45fSAndroid Build Coastguard Worker     // Drain all pending events, keep the last vsync.
129*38e8c45fSAndroid Build Coastguard Worker     nsecs_t vsyncTimestamp;
130*38e8c45fSAndroid Build Coastguard Worker     PhysicalDisplayId vsyncDisplayId;
131*38e8c45fSAndroid Build Coastguard Worker     uint32_t vsyncCount;
132*38e8c45fSAndroid Build Coastguard Worker     VsyncEventData vsyncEventData;
133*38e8c45fSAndroid Build Coastguard Worker     if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
134*38e8c45fSAndroid Build Coastguard Worker         ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
135*38e8c45fSAndroid Build Coastguard Worker               ", displayId=%s, count=%d, vsyncId=%" PRId64,
136*38e8c45fSAndroid Build Coastguard Worker               this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
137*38e8c45fSAndroid Build Coastguard Worker               vsyncEventData.preferredVsyncId());
138*38e8c45fSAndroid Build Coastguard Worker         mWaitingForVsync = false;
139*38e8c45fSAndroid Build Coastguard Worker         mLastVsyncCount = vsyncCount;
140*38e8c45fSAndroid Build Coastguard Worker         dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
141*38e8c45fSAndroid Build Coastguard Worker     }
142*38e8c45fSAndroid Build Coastguard Worker 
143*38e8c45fSAndroid Build Coastguard Worker     if (mWaitingForVsync) {
144*38e8c45fSAndroid Build Coastguard Worker         const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
145*38e8c45fSAndroid Build Coastguard Worker         const nsecs_t vsyncScheduleDelay = currentTime - mLastScheduleVsyncTime;
146*38e8c45fSAndroid Build Coastguard Worker         if (vsyncScheduleDelay > WAITING_FOR_VSYNC_TIMEOUT) {
147*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
148*38e8c45fSAndroid Build Coastguard Worker             mWaitingForVsync = false;
149*38e8c45fSAndroid Build Coastguard Worker             dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
150*38e8c45fSAndroid Build Coastguard Worker                           ++mLastVsyncCount, vsyncEventData /* empty data */);
151*38e8c45fSAndroid Build Coastguard Worker         }
152*38e8c45fSAndroid Build Coastguard Worker     }
153*38e8c45fSAndroid Build Coastguard Worker 
154*38e8c45fSAndroid Build Coastguard Worker     return 1; // keep the callback
155*38e8c45fSAndroid Build Coastguard Worker }
156*38e8c45fSAndroid Build Coastguard Worker 
processPendingEvents(nsecs_t * outTimestamp,PhysicalDisplayId * outDisplayId,uint32_t * outCount,VsyncEventData * outVsyncEventData)157*38e8c45fSAndroid Build Coastguard Worker bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
158*38e8c45fSAndroid Build Coastguard Worker                                                   PhysicalDisplayId* outDisplayId,
159*38e8c45fSAndroid Build Coastguard Worker                                                   uint32_t* outCount,
160*38e8c45fSAndroid Build Coastguard Worker                                                   VsyncEventData* outVsyncEventData) {
161*38e8c45fSAndroid Build Coastguard Worker     bool gotVsync = false;
162*38e8c45fSAndroid Build Coastguard Worker     DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
163*38e8c45fSAndroid Build Coastguard Worker     ssize_t n;
164*38e8c45fSAndroid Build Coastguard Worker     while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
165*38e8c45fSAndroid Build Coastguard Worker         ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
166*38e8c45fSAndroid Build Coastguard Worker         mFrameRateOverrides.reserve(n);
167*38e8c45fSAndroid Build Coastguard Worker         for (ssize_t i = 0; i < n; i++) {
168*38e8c45fSAndroid Build Coastguard Worker             const DisplayEventReceiver::Event& ev = buf[i];
169*38e8c45fSAndroid Build Coastguard Worker             switch (ev.header.type) {
170*38e8c45fSAndroid Build Coastguard Worker                 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
171*38e8c45fSAndroid Build Coastguard Worker                     // Later vsync events will just overwrite the info from earlier
172*38e8c45fSAndroid Build Coastguard Worker                     // ones. That's fine, we only care about the most recent.
173*38e8c45fSAndroid Build Coastguard Worker                     gotVsync = true;
174*38e8c45fSAndroid Build Coastguard Worker                     *outTimestamp = ev.header.timestamp;
175*38e8c45fSAndroid Build Coastguard Worker                     *outDisplayId = ev.header.displayId;
176*38e8c45fSAndroid Build Coastguard Worker                     *outCount = ev.vsync.count;
177*38e8c45fSAndroid Build Coastguard Worker                     *outVsyncEventData = ev.vsync.vsyncData;
178*38e8c45fSAndroid Build Coastguard Worker 
179*38e8c45fSAndroid Build Coastguard Worker                     // Trace the RenderRate for this app
180*38e8c45fSAndroid Build Coastguard Worker                     if (ATRACE_ENABLED() && flags::trace_frame_rate_override()) {
181*38e8c45fSAndroid Build Coastguard Worker                         const auto frameInterval = ev.vsync.vsyncData.frameInterval;
182*38e8c45fSAndroid Build Coastguard Worker                         int fps = frameInterval > 0 ? 1e9f / frameInterval : 0;
183*38e8c45fSAndroid Build Coastguard Worker                         ATRACE_INT("RenderRate", fps);
184*38e8c45fSAndroid Build Coastguard Worker                     }
185*38e8c45fSAndroid Build Coastguard Worker                     break;
186*38e8c45fSAndroid Build Coastguard Worker                 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
187*38e8c45fSAndroid Build Coastguard Worker                     if (ev.hotplug.connectionError == 0) {
188*38e8c45fSAndroid Build Coastguard Worker                         dispatchHotplug(ev.header.timestamp, ev.header.displayId,
189*38e8c45fSAndroid Build Coastguard Worker                                         ev.hotplug.connected);
190*38e8c45fSAndroid Build Coastguard Worker                     } else {
191*38e8c45fSAndroid Build Coastguard Worker                         dispatchHotplugConnectionError(ev.header.timestamp,
192*38e8c45fSAndroid Build Coastguard Worker                                                        ev.hotplug.connectionError);
193*38e8c45fSAndroid Build Coastguard Worker                     }
194*38e8c45fSAndroid Build Coastguard Worker                     break;
195*38e8c45fSAndroid Build Coastguard Worker                 case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
196*38e8c45fSAndroid Build Coastguard Worker                     dispatchModeChanged(ev.header.timestamp, ev.header.displayId,
197*38e8c45fSAndroid Build Coastguard Worker                                         ev.modeChange.modeId, ev.modeChange.vsyncPeriod);
198*38e8c45fSAndroid Build Coastguard Worker                     break;
199*38e8c45fSAndroid Build Coastguard Worker                 case DisplayEventReceiver::DISPLAY_EVENT_NULL:
200*38e8c45fSAndroid Build Coastguard Worker                     dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
201*38e8c45fSAndroid Build Coastguard Worker                     break;
202*38e8c45fSAndroid Build Coastguard Worker                 case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
203*38e8c45fSAndroid Build Coastguard Worker                     mFrameRateOverrides.emplace_back(ev.frameRateOverride);
204*38e8c45fSAndroid Build Coastguard Worker                     break;
205*38e8c45fSAndroid Build Coastguard Worker                 case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
206*38e8c45fSAndroid Build Coastguard Worker                     dispatchFrameRateOverrides(ev.header.timestamp, ev.header.displayId,
207*38e8c45fSAndroid Build Coastguard Worker                                                std::move(mFrameRateOverrides));
208*38e8c45fSAndroid Build Coastguard Worker                     break;
209*38e8c45fSAndroid Build Coastguard Worker                 case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
210*38e8c45fSAndroid Build Coastguard Worker                     dispatchHdcpLevelsChanged(ev.header.displayId,
211*38e8c45fSAndroid Build Coastguard Worker                                               ev.hdcpLevelsChange.connectedLevel,
212*38e8c45fSAndroid Build Coastguard Worker                                               ev.hdcpLevelsChange.maxLevel);
213*38e8c45fSAndroid Build Coastguard Worker                     break;
214*38e8c45fSAndroid Build Coastguard Worker                 case DisplayEventReceiver::DISPLAY_EVENT_MODE_REJECTION:
215*38e8c45fSAndroid Build Coastguard Worker                     dispatchModeRejected(ev.header.displayId, ev.modeRejection.modeId);
216*38e8c45fSAndroid Build Coastguard Worker                     break;
217*38e8c45fSAndroid Build Coastguard Worker                 default:
218*38e8c45fSAndroid Build Coastguard Worker                     ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
219*38e8c45fSAndroid Build Coastguard Worker                     break;
220*38e8c45fSAndroid Build Coastguard Worker             }
221*38e8c45fSAndroid Build Coastguard Worker         }
222*38e8c45fSAndroid Build Coastguard Worker     }
223*38e8c45fSAndroid Build Coastguard Worker     if (n < 0) {
224*38e8c45fSAndroid Build Coastguard Worker         ALOGW("Failed to get events from display event dispatcher, status=%d", status_t(n));
225*38e8c45fSAndroid Build Coastguard Worker     }
226*38e8c45fSAndroid Build Coastguard Worker     return gotVsync;
227*38e8c45fSAndroid Build Coastguard Worker }
228*38e8c45fSAndroid Build Coastguard Worker 
getLatestVsyncEventData(ParcelableVsyncEventData * outVsyncEventData) const229*38e8c45fSAndroid Build Coastguard Worker status_t DisplayEventDispatcher::getLatestVsyncEventData(
230*38e8c45fSAndroid Build Coastguard Worker         ParcelableVsyncEventData* outVsyncEventData) const {
231*38e8c45fSAndroid Build Coastguard Worker     return mReceiver.getLatestVsyncEventData(outVsyncEventData);
232*38e8c45fSAndroid Build Coastguard Worker }
233*38e8c45fSAndroid Build Coastguard Worker 
234*38e8c45fSAndroid Build Coastguard Worker } // namespace android
235