1 /*
2 * Copyright (C) 2016 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 "hwc-drm-event-listener"
18
19 #include "drmeventlistener.h"
20
21 #include <assert.h>
22 #include <drm/samsung_drm.h>
23 #include <errno.h>
24 #include <hardware/hardware.h>
25 #include <hardware/hwcomposer.h>
26 #include <inttypes.h>
27 #include <linux/netlink.h>
28 #include <log/log.h>
29 #include <sys/socket.h>
30 #include <utils/String8.h>
31 #include <xf86drm.h>
32
33 #include "drmdevice.h"
34
35 namespace android {
36
DrmEventListener(DrmDevice * drm)37 DrmEventListener::DrmEventListener(DrmDevice *drm)
38 : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY), drm_(drm) {
39 }
40
~DrmEventListener()41 DrmEventListener::~DrmEventListener() {
42 Exit();
43 }
44
Init()45 int DrmEventListener::Init() {
46 struct epoll_event ev;
47 char buffer[1024];
48
49 /* Open User Event File Descriptor */
50 uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
51 if (uevent_fd_.get() < 0) {
52 ALOGE("Failed to open uevent socket: %s", strerror(errno));
53 return uevent_fd_.get();
54 }
55
56 struct sockaddr_nl addr;
57 memset(&addr, 0, sizeof(addr));
58 addr.nl_family = AF_NETLINK;
59 addr.nl_pid = 0;
60 addr.nl_groups = 0xFFFFFFFF;
61
62 int ret = bind(uevent_fd_.get(), (struct sockaddr *)&addr, sizeof(addr));
63 if (ret) {
64 ALOGE("Failed to bind uevent socket: %s", strerror(errno));
65 return -errno;
66 }
67
68 /* Open TUI Event File Descriptor */
69 tuievent_fd_.Set(open(kTUIStatusPath, O_RDONLY));
70 if (tuievent_fd_.get() < 0) {
71 ALOGE("Failed to open sysfs(%s) for TUI event: %s", kTUIStatusPath, strerror(errno));
72 } else {
73 /* Read garbage data once */
74 pread(tuievent_fd_.get(), &buffer, sizeof(buffer), 0);
75
76 ev.events = EPOLLPRI;
77 ev.data.fd = tuievent_fd_.get();
78 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, tuievent_fd_.get(), &ev) < 0)
79 ALOGE("Failed to add tui fd into epoll: %s", strerror(errno));
80 }
81
82 /* Set EPoll*/
83 epoll_fd_.Set(epoll_create(maxFds));
84 if (epoll_fd_.get() < 0) {
85 ALOGE("Failed to create epoll: %s", strerror(errno));
86 return epoll_fd_.get();
87 }
88
89 ev.events = EPOLLIN;
90 ev.data.fd = uevent_fd_.get();
91 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, uevent_fd_.get(), &ev) < 0) {
92 ALOGE("Failed to add uevent fd into epoll: %s", strerror(errno));
93 return -errno;
94 }
95
96 ev.events = EPOLLIN;
97 ev.data.fd = drm_->fd();
98 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, drm_->fd(), &ev) < 0) {
99 ALOGE("Failed to add drm fd into epoll: %s", strerror(errno));
100 return -errno;
101 }
102
103 return 0;
104 }
105
RegisterHotplugHandler(const std::shared_ptr<DrmEventHandler> & handler)106 void DrmEventListener::RegisterHotplugHandler(const std::shared_ptr<DrmEventHandler> &handler) {
107 assert(!hotplug_handler_);
108 hotplug_handler_ = handler;
109 }
110
UnRegisterHotplugHandler(const std::shared_ptr<DrmEventHandler> & handler)111 void DrmEventListener::UnRegisterHotplugHandler(const std::shared_ptr<DrmEventHandler> &handler) {
112 if (handler.get() == hotplug_handler_.get())
113 hotplug_handler_ = NULL;
114 }
115
RegisterHistogramHandler(const std::shared_ptr<DrmHistogramEventHandler> & handler)116 void DrmEventListener::RegisterHistogramHandler(
117 const std::shared_ptr<DrmHistogramEventHandler> &handler) {
118 assert(!histogram_handler_);
119 histogram_handler_ = handler;
120 }
121
UnRegisterHistogramHandler(const std::shared_ptr<DrmHistogramEventHandler> & handler)122 void DrmEventListener::UnRegisterHistogramHandler(
123 const std::shared_ptr<DrmHistogramEventHandler> &handler) {
124 if (handler.get() == histogram_handler_.get())
125 histogram_handler_ = NULL;
126 }
127
RegisterHistogramChannelHandler(const std::shared_ptr<DrmHistogramChannelEventHandler> & handler)128 void DrmEventListener::RegisterHistogramChannelHandler(
129 const std::shared_ptr<DrmHistogramChannelEventHandler> &handler) {
130 assert(!histogram_channel_handler_);
131
132 if (handler) {
133 histogram_channel_handler_ = handler;
134 } else {
135 ALOGE("%s: failed to register, handler is nullptr", __func__);
136 }
137 }
138
UnRegisterHistogramChannelHandler(const std::shared_ptr<DrmHistogramChannelEventHandler> & handler)139 void DrmEventListener::UnRegisterHistogramChannelHandler(
140 const std::shared_ptr<DrmHistogramChannelEventHandler> &handler) {
141 if (handler.get() == histogram_channel_handler_.get()) {
142 histogram_channel_handler_ = NULL;
143 } else {
144 ALOGE("%s: failed to unregister, handler(%p), histogram_channel_handler(%p)", __func__,
145 handler.get(), histogram_channel_handler_.get());
146 }
147 }
148
RegisterContextHistogramHandler(const std::shared_ptr<DrmContextHistogramEventHandler> & handler)149 void DrmEventListener::RegisterContextHistogramHandler(
150 const std::shared_ptr<DrmContextHistogramEventHandler> &handler) {
151 assert(!context_histogram_handler_);
152
153 if (handler) {
154 context_histogram_handler_ = handler;
155 } else {
156 ALOGE("%s: failed to register, handler is nullptr", __func__);
157 }
158 }
159
UnRegisterContextHistogramHandler(const std::shared_ptr<DrmContextHistogramEventHandler> & handler)160 void DrmEventListener::UnRegisterContextHistogramHandler(
161 const std::shared_ptr<DrmContextHistogramEventHandler> &handler) {
162 if (handler.get() == context_histogram_handler_.get()) {
163 context_histogram_handler_ = NULL;
164 } else {
165 ALOGE("%s: failed to unregister, handler(%p), context_histogram_handler(%p)", __func__,
166 handler.get(), context_histogram_handler_.get());
167 }
168 }
169
RegisterTUIHandler(const std::shared_ptr<DrmTUIEventHandler> & handler)170 void DrmEventListener::RegisterTUIHandler(const std::shared_ptr<DrmTUIEventHandler> &handler) {
171 if (tui_handler_) {
172 ALOGE("TUI handler was already registered");
173 return;
174 }
175 tui_handler_ = handler;
176 }
177
UnRegisterTUIHandler(const std::shared_ptr<DrmTUIEventHandler> & handler)178 void DrmEventListener::UnRegisterTUIHandler(const std::shared_ptr<DrmTUIEventHandler> &handler) {
179 if (handler.get() == tui_handler_.get())
180 tui_handler_ = NULL;
181 }
182
RegisterPanelIdleHandler(const std::shared_ptr<DrmPanelIdleEventHandler> & handler)183 void DrmEventListener::RegisterPanelIdleHandler(
184 const std::shared_ptr<DrmPanelIdleEventHandler> &handler) {
185 assert(!panel_idle_handler_);
186 panel_idle_handler_ = handler;
187 }
188
UnRegisterPanelIdleHandler(const std::shared_ptr<DrmPanelIdleEventHandler> & handler)189 void DrmEventListener::UnRegisterPanelIdleHandler(
190 const std::shared_ptr<DrmPanelIdleEventHandler> &handler) {
191 if (handler.get() == panel_idle_handler_.get())
192 panel_idle_handler_ = NULL;
193 }
194
RegisterSysfsHandler(std::shared_ptr<DrmSysfsEventHandler> handler)195 int DrmEventListener::RegisterSysfsHandler(std::shared_ptr<DrmSysfsEventHandler> handler) {
196 if (!handler)
197 return -EINVAL;
198 if (handler->getFd() < 0)
199 return -EINVAL;
200 std::scoped_lock lock(mutex_);
201 if (sysfs_handlers_.find(handler->getFd()) != sysfs_handlers_.end()) {
202 ALOGE("%s: DrmSysfsEventHandler for fd:%d has been added to epoll", __func__, handler->getFd());
203 return -EINVAL;
204 }
205
206 struct epoll_event ev;
207 ev.events = EPOLLPRI;
208 ev.data.fd = handler->getFd();
209 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, handler->getFd(), &ev) < 0) {
210 ALOGE("%s: Failed to add fd into epoll: %s", __func__, strerror(errno));
211 return -errno;
212 }
213 sysfs_handlers_.emplace(handler->getFd(), std::move(handler));
214 return 0;
215 }
216
UnRegisterSysfsHandler(int sysfs_fd)217 int DrmEventListener::UnRegisterSysfsHandler(int sysfs_fd) {
218 std::scoped_lock lock(mutex_);
219 auto it = sysfs_handlers_.find(sysfs_fd);
220 if (it == sysfs_handlers_.end()) {
221 ALOGE("%s: DrmSysfsEventHandler for fd:%d not found", __func__, sysfs_fd);
222 return -EINVAL;
223 }
224 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, sysfs_fd, nullptr) < 0) {
225 ALOGE("%s: Failed to remove fd from epoll: %s", __func__, strerror(errno));
226 return -errno;
227 }
228 sysfs_handlers_.erase(it);
229 return 0;
230 }
231
RegisterPropertyUpdateHandler(const std::shared_ptr<DrmPropertyUpdateHandler> & handler)232 void DrmEventListener::RegisterPropertyUpdateHandler(
233 const std::shared_ptr<DrmPropertyUpdateHandler> &handler) {
234 assert(!drm_prop_update_handler_);
235 drm_prop_update_handler_ = handler;
236 }
237
UnRegisterPropertyUpdateHandler(const std::shared_ptr<DrmPropertyUpdateHandler> & handler)238 void DrmEventListener::UnRegisterPropertyUpdateHandler(
239 const std::shared_ptr<DrmPropertyUpdateHandler> &handler) {
240 if (handler.get() == drm_prop_update_handler_.get())
241 drm_prop_update_handler_ = NULL;
242 }
243
IsDrmInTUI()244 bool DrmEventListener::IsDrmInTUI() {
245 char buffer[1024];
246 int ret;
247
248 if (tuievent_fd_.get() >= 0) {
249 ret = pread(tuievent_fd_.get(), &buffer, sizeof(buffer), 0);
250 if (ret == 0) {
251 return false;
252 } else if (ret < 0) {
253 ALOGE("Got error reading TUI event %s", strerror(errno));
254 return false;
255 }
256
257 return atoi(buffer) == 1 ? true : false;
258 }
259
260 return false;
261 }
262
FlipHandler(int,unsigned int,unsigned int tv_sec,unsigned int tv_usec,void * user_data)263 void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */,
264 unsigned int tv_sec, unsigned int tv_usec,
265 void *user_data) {
266 DrmEventHandler *handler = (DrmEventHandler *)user_data;
267 if (!handler)
268 return;
269
270 handler->handleEvent((uint64_t)tv_sec * 1000 * 1000 + tv_usec);
271 delete handler;
272 }
273
UEventHandler()274 void DrmEventListener::UEventHandler() {
275 char buffer[1024];
276 int ret;
277
278 struct timespec ts;
279 uint64_t timestamp = 0;
280 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
281 if (!ret)
282 timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
283 else
284 ALOGE("Failed to get monotonic clock on hotplug %d", ret);
285
286 ret = read(uevent_fd_.get(), &buffer, sizeof(buffer));
287 if (ret == 0) {
288 return;
289 } else if (ret < 0) {
290 ALOGE("Got error reading uevent %d", ret);
291 return;
292 }
293
294 bool drm_event = false, hotplug_event = false;
295 bool have_connector_id = false, have_property_id = false;
296 unsigned connector_id = 0;
297 unsigned updated_property_id = 0;
298 for (int i = 0; i < ret;) {
299 char *event = buffer + i;
300
301 if (!strcmp(event, "DEVTYPE=drm_minor")) {
302 drm_event = true;
303 } else if (!strncmp(event, "PANEL_IDLE_ENTER=", strlen("PANEL_IDLE_ENTER="))) {
304 panel_idle_handler_->handleIdleEnterEvent(event);
305 } else if (!strcmp(event, "HOTPLUG=1")) {
306 hotplug_event = true;
307 } else if (sscanf(event, "CONNECTOR=%u", &connector_id) == 1) {
308 have_connector_id = true;
309 } else if (sscanf(event, "PROPERTY=%u", &updated_property_id) == 1) {
310 have_property_id = true;
311 }
312
313 i += strlen(event) + 1;
314 }
315
316 // Property updates also have HOTPLUG=1 string, so must be handled
317 // first. Actual hotplug events don't have property id.
318 if (have_connector_id && have_property_id) {
319 if (drm_prop_update_handler_)
320 drm_prop_update_handler_->handleDrmPropertyUpdate(connector_id, updated_property_id);
321 return;
322 }
323
324 if (drm_event && hotplug_event) {
325 if (!hotplug_handler_)
326 return;
327
328 hotplug_handler_->handleEvent(timestamp);
329 }
330 }
331
DRMEventHandler()332 void DrmEventListener::DRMEventHandler() {
333 char buffer[1024];
334 int len, i;
335 struct drm_event *e;
336 struct drm_event_vblank *vblank;
337 struct exynos_drm_histogram_event *histo;
338 void *user_data;
339
340 len = read(drm_->fd(), &buffer, sizeof(buffer));
341 if (len == 0) return;
342 if (len < (int)sizeof(*e)) return;
343
344 i = 0;
345 while (i < len) {
346 e = (struct drm_event *)(buffer + i);
347 switch (e->type) {
348 case EXYNOS_DRM_HISTOGRAM_EVENT:
349 if (histogram_handler_) {
350 histo = (struct exynos_drm_histogram_event *)e;
351 histogram_handler_->handleHistogramEvent(histo->crtc_id,
352 (void *)&(histo->bins));
353 }
354 break;
355 #if defined(EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT)
356 case EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT:
357 if (histogram_channel_handler_) {
358 histogram_channel_handler_->handleHistogramChannelEvent((void *)e);
359 } else {
360 ALOGE("%s: no valid histogram channel event handler", __func__);
361 }
362 break;
363 #endif
364 #if defined(EXYNOS_DRM_CONTEXT_HISTOGRAM_EVENT)
365 case EXYNOS_DRM_CONTEXT_HISTOGRAM_EVENT:
366 if (context_histogram_handler_) {
367 context_histogram_handler_->handleContextHistogramEvent((void *)e);
368 } else {
369 ALOGE("%s: no valid context histogram event handler", __func__);
370 }
371 break;
372 #endif
373 case DRM_EVENT_FLIP_COMPLETE:
374 vblank = (struct drm_event_vblank *)e;
375 user_data = (void *)(unsigned long)(vblank->user_data);
376 FlipHandler(drm_->fd(), vblank->sequence, vblank->tv_sec, vblank->tv_usec,
377 user_data);
378 break;
379 case DRM_EVENT_VBLANK:
380 case DRM_EVENT_CRTC_SEQUENCE:
381 /* These DRM events are not handled */
382 break;
383 default:
384 break;
385 }
386 i += e->length;
387 }
388
389 return;
390 }
391
TUIEventHandler()392 void DrmEventListener::TUIEventHandler() {
393 if (!tui_handler_) {
394 ALOGE("%s:: tui event handler is not valid", __func__);
395 return;
396 }
397
398 tui_handler_->handleTUIEvent();
399 }
400
SysfsEventHandler(int fd)401 void DrmEventListener::SysfsEventHandler(int fd) {
402 std::shared_ptr<DrmSysfsEventHandler> handler;
403 {
404 std::scoped_lock lock(mutex_);
405 // Copy the shared_ptr to avoid the handler object gets destroyed
406 // while it's handling the event without holding mutex_
407 auto it = sysfs_handlers_.find(fd);
408 if (it != sysfs_handlers_.end())
409 handler = it->second;
410 }
411 if (handler) {
412 handler->handleSysfsEvent();
413 } else {
414 ALOGW("Unhandled sysfs event from fd:%d", fd);
415 }
416 }
417
Routine()418 void DrmEventListener::Routine() {
419 struct epoll_event events[maxFds];
420 int nfds, n;
421
422 do {
423 nfds = epoll_wait(epoll_fd_.get(), events, maxFds, -1);
424 } while (nfds <= 0);
425
426 for (n = 0; n < nfds; n++) {
427 if (events[n].events & EPOLLIN) {
428 if (events[n].data.fd == uevent_fd_.get()) {
429 UEventHandler();
430 } else if (events[n].data.fd == drm_->fd()) {
431 DRMEventHandler();
432 }
433 } else if (events[n].events & EPOLLPRI) {
434 if (tuievent_fd_.get() >= 0 && events[n].data.fd == tuievent_fd_.get()) {
435 TUIEventHandler();
436 } else {
437 SysfsEventHandler(events[n].data.fd);
438 }
439 }
440 }
441 }
442 } // namespace android
443