• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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