• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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 #include "DrmPresenter.h"
18 
19 #include <cros_gralloc_handle.h>
20 #include <linux/netlink.h>
21 #include <sys/socket.h>
22 
23 using android::base::guest::AutoReadLock;
24 using android::base::guest::AutoWriteLock;
25 using android::base::guest::ReadWriteLock;
26 
27 namespace android {
28 
init(const HotplugCallback & cb)29 bool DrmPresenter::init(const HotplugCallback& cb) {
30   DEBUG_LOG("%s", __FUNCTION__);
31 
32   mHotplugCallback = cb;
33   mFd = android::base::unique_fd(open("/dev/dri/card0", O_RDWR | O_CLOEXEC));
34   if (mFd < 0) {
35     ALOGE("%s HWC2::Error opening DrmPresenter device: %d", __FUNCTION__,
36           errno);
37     return false;
38   }
39 
40   int univRet = drmSetClientCap(mFd.get(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
41   if (univRet) {
42     ALOGE("%s: fail to set universal plane %d\n", __FUNCTION__, univRet);
43     return false;
44   }
45 
46   int atomicRet = drmSetClientCap(mFd.get(), DRM_CLIENT_CAP_ATOMIC, 1);
47   if (atomicRet) {
48     ALOGE("%s: fail to set atomic operation %d, %d\n", __FUNCTION__, atomicRet,
49           errno);
50     return false;
51   }
52 
53   {
54     AutoWriteLock lock(mStateMutex);
55     bool initDrmRet = initDrmElementsLocked();
56     if (initDrmRet) {
57       ALOGD("%s: Successfully initialized DRM backend", __FUNCTION__);
58     } else {
59       ALOGE("%s: Failed to initialize DRM backend", __FUNCTION__);
60       return false;
61     }
62   }
63 
64   mDrmEventListener = sp<DrmEventListener>::make(*this);
65   if (mDrmEventListener->init()) {
66     ALOGD("%s: Successfully initialized DRM event listener", __FUNCTION__);
67   } else {
68     ALOGE("%s: Failed to initialize DRM event listener", __FUNCTION__);
69   }
70   mDrmEventListener->run("", ANDROID_PRIORITY_URGENT_DISPLAY);
71 
72   return true;
73 }
74 
initDrmElementsLocked()75 bool DrmPresenter::initDrmElementsLocked() {
76   drmModeRes* res;
77   static const int32_t kUmPerInch = 25400;
78 
79   res = drmModeGetResources(mFd.get());
80   if (res == nullptr) {
81     ALOGE("%s HWC2::Error reading drm resources: %d", __FUNCTION__, errno);
82     mFd.reset();
83     return false;
84   }
85 
86   ALOGD(
87       "drmModeRes count fbs %d crtc %d connector %d encoder %d min w %d max w "
88       "%d min h %d max h %d",
89       res->count_fbs, res->count_crtcs, res->count_connectors,
90       res->count_encoders, res->min_width, res->max_width, res->min_height,
91       res->max_height);
92 
93   for (uint32_t i = 0; i < res->count_crtcs; i++) {
94     DrmCrtc crtc = {};
95 
96     drmModeCrtcPtr c = drmModeGetCrtc(mFd.get(), res->crtcs[i]);
97     crtc.mId = c->crtc_id;
98 
99     drmModeObjectPropertiesPtr crtcProps =
100         drmModeObjectGetProperties(mFd.get(), c->crtc_id, DRM_MODE_OBJECT_CRTC);
101 
102     for (uint32_t crtcPropsIndex = 0; crtcPropsIndex < crtcProps->count_props;
103          crtcPropsIndex++) {
104       drmModePropertyPtr crtcProp =
105           drmModeGetProperty(mFd.get(), crtcProps->props[crtcPropsIndex]);
106 
107       if (!strcmp(crtcProp->name, "OUT_FENCE_PTR")) {
108         crtc.mFencePropertyId = crtcProp->prop_id;
109       } else if (!strcmp(crtcProp->name, "ACTIVE")) {
110         crtc.mActivePropertyId = crtcProp->prop_id;
111       } else if (!strcmp(crtcProp->name, "MODE_ID")) {
112         crtc.mModePropertyId = crtcProp->prop_id;
113       }
114 
115       drmModeFreeProperty(crtcProp);
116     }
117 
118     drmModeFreeObjectProperties(crtcProps);
119 
120     mCrtcs.push_back(crtc);
121   }
122 
123   drmModePlaneResPtr planeRes = drmModeGetPlaneResources(mFd.get());
124   for (uint32_t i = 0; i < planeRes->count_planes; ++i) {
125     DrmPlane plane = {};
126 
127     drmModePlanePtr p = drmModeGetPlane(mFd.get(), planeRes->planes[i]);
128     plane.mId = p->plane_id;
129 
130     ALOGD(
131         "%s: plane id: %u crtcid %u fbid %u crtc xy %d %d xy %d %d "
132         "possible ctrcs 0x%x",
133         __FUNCTION__, p->plane_id, p->crtc_id, p->fb_id, p->crtc_x, p->crtc_y,
134         p->x, p->y, p->possible_crtcs);
135 
136     drmModeObjectPropertiesPtr planeProps =
137         drmModeObjectGetProperties(mFd.get(), plane.mId, DRM_MODE_OBJECT_PLANE);
138 
139     for (uint32_t planePropIndex = 0; planePropIndex < planeProps->count_props;
140          ++planePropIndex) {
141       drmModePropertyPtr planeProp =
142           drmModeGetProperty(mFd.get(), planeProps->props[planePropIndex]);
143 
144       if (!strcmp(planeProp->name, "CRTC_ID")) {
145         plane.mCrtcPropertyId = planeProp->prop_id;
146       } else if (!strcmp(planeProp->name, "FB_ID")) {
147         plane.mFbPropertyId = planeProp->prop_id;
148       } else if (!strcmp(planeProp->name, "CRTC_X")) {
149         plane.mCrtcXPropertyId = planeProp->prop_id;
150       } else if (!strcmp(planeProp->name, "CRTC_Y")) {
151         plane.mCrtcYPropertyId = planeProp->prop_id;
152       } else if (!strcmp(planeProp->name, "CRTC_W")) {
153         plane.mCrtcWPropertyId = planeProp->prop_id;
154       } else if (!strcmp(planeProp->name, "CRTC_H")) {
155         plane.mCrtcHPropertyId = planeProp->prop_id;
156       } else if (!strcmp(planeProp->name, "SRC_X")) {
157         plane.mSrcXPropertyId = planeProp->prop_id;
158       } else if (!strcmp(planeProp->name, "SRC_Y")) {
159         plane.mSrcYPropertyId = planeProp->prop_id;
160       } else if (!strcmp(planeProp->name, "SRC_W")) {
161         plane.mSrcWPropertyId = planeProp->prop_id;
162       } else if (!strcmp(planeProp->name, "SRC_H")) {
163         plane.mSrcHPropertyId = planeProp->prop_id;
164       } else if (!strcmp(planeProp->name, "type")) {
165         plane.mTypePropertyId = planeProp->prop_id;
166         uint64_t type = planeProp->values[0];
167         switch (type) {
168           case DRM_PLANE_TYPE_OVERLAY:
169             plane.mType = type;
170             ALOGD("%s: plane %" PRIu32 " is DRM_PLANE_TYPE_OVERLAY",
171                   __FUNCTION__, plane.mId);
172             break;
173           case DRM_PLANE_TYPE_PRIMARY:
174             plane.mType = type;
175             ALOGD("%s: plane %" PRIu32 " is DRM_PLANE_TYPE_PRIMARY",
176                   __FUNCTION__, plane.mId);
177             break;
178           default:
179             break;
180         }
181       }
182 
183       drmModeFreeProperty(planeProp);
184     }
185 
186     drmModeFreeObjectProperties(planeProps);
187 
188     bool isPrimaryOrOverlay = plane.mType == DRM_PLANE_TYPE_OVERLAY ||
189                               plane.mType == DRM_PLANE_TYPE_PRIMARY;
190     if (isPrimaryOrOverlay) {
191       for (uint32_t j = 0; j < mCrtcs.size(); j++) {
192         if ((0x1 << j) & p->possible_crtcs) {
193           ALOGD("%s: plane %" PRIu32 " compatible with crtc mask %" PRIu32,
194                 __FUNCTION__, plane.mId, p->possible_crtcs);
195           if (mCrtcs[j].mPlaneId == -1) {
196             mCrtcs[j].mPlaneId = plane.mId;
197             ALOGD("%s: plane %" PRIu32 " associated with crtc %" PRIu32,
198                   __FUNCTION__, plane.mId, j);
199             break;
200           }
201         }
202       }
203     }
204 
205     drmModeFreePlane(p);
206     mPlanes[plane.mId] = plane;
207   }
208   drmModeFreePlaneResources(planeRes);
209 
210   for (uint32_t i = 0; i < res->count_connectors; ++i) {
211     DrmConnector connector = {};
212     connector.mId = res->connectors[i];
213 
214     {
215       drmModeObjectPropertiesPtr connectorProps = drmModeObjectGetProperties(
216           mFd.get(), connector.mId, DRM_MODE_OBJECT_CONNECTOR);
217 
218       for (uint32_t connectorPropIndex = 0;
219            connectorPropIndex < connectorProps->count_props;
220            ++connectorPropIndex) {
221         drmModePropertyPtr connectorProp = drmModeGetProperty(
222             mFd.get(), connectorProps->props[connectorPropIndex]);
223         if (!strcmp(connectorProp->name, "CRTC_ID")) {
224           connector.mCrtcPropertyId = connectorProp->prop_id;
225         } else if (!strcmp(connectorProp->name, "EDID")) {
226           connector.mEdidBlobId = connectorProps->prop_values[connectorPropIndex];
227         }
228         drmModeFreeProperty(connectorProp);
229       }
230 
231       drmModeFreeObjectProperties(connectorProps);
232     }
233     {
234       drmModeConnector* c = drmModeGetConnector(mFd.get(), connector.mId);
235       if (c == nullptr) {
236         ALOGE("%s: Failed to get connector %" PRIu32 ": %d", __FUNCTION__,
237               connector.mId, errno);
238         return false;
239       }
240       connector.connection = c->connection;
241       if (c->count_modes > 0) {
242         memcpy(&connector.mMode, &c->modes[0], sizeof(drmModeModeInfo));
243         drmModeCreatePropertyBlob(mFd.get(), &connector.mMode,
244                                   sizeof(connector.mMode),
245                                   &connector.mModeBlobId);
246 
247         // Dots per 1000 inches
248         connector.dpiX =
249             c->mmWidth ? (c->modes[0].hdisplay * kUmPerInch) / (c->mmWidth)
250                        : -1;
251         // Dots per 1000 inches
252         connector.dpiY =
253             c->mmHeight ? (c->modes[0].vdisplay * kUmPerInch) / (c->mmHeight)
254                         : -1;
255       }
256       ALOGD("%s connector %" PRIu32 " dpiX %" PRIi32 " dpiY %" PRIi32
257             " connection %d",
258             __FUNCTION__, connector.mId, connector.dpiX, connector.dpiY,
259             connector.connection);
260 
261       drmModeFreeConnector(c);
262 
263       connector.mRefreshRateAsFloat =
264           1000.0f * connector.mMode.clock /
265           ((float)connector.mMode.vtotal * (float)connector.mMode.htotal);
266       connector.mRefreshRateAsInteger =
267           (uint32_t)(connector.mRefreshRateAsFloat + 0.5f);
268     }
269 
270     mConnectors.push_back(connector);
271   }
272 
273   drmModeFreeResources(res);
274   return true;
275 }
276 
resetDrmElementsLocked()277 void DrmPresenter::resetDrmElementsLocked() {
278   for (auto& c : mConnectors) {
279     if (c.mModeBlobId) {
280       if (drmModeDestroyPropertyBlob(mFd.get(), c.mModeBlobId)) {
281         ALOGE("%s: Error destroy PropertyBlob %" PRIu32, __func__,
282               c.mModeBlobId);
283       }
284     }
285   }
286   mConnectors.clear();
287   mCrtcs.clear();
288   mPlanes.clear();
289 }
290 
getDrmFB(hwc_drm_bo_t & bo)291 int DrmPresenter::getDrmFB(hwc_drm_bo_t& bo) {
292   int ret = drmPrimeFDToHandle(mFd.get(), bo.prime_fds[0], &bo.gem_handles[0]);
293   if (ret) {
294     ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__,
295           strerror(errno), errno);
296     return -1;
297   }
298   ret = drmModeAddFB2(mFd.get(), bo.width, bo.height, bo.format, bo.gem_handles,
299                       bo.pitches, bo.offsets, &bo.fb_id, 0);
300   if (ret) {
301     ALOGE("%s: drmModeAddFB2 failed: %s (errno %d)", __FUNCTION__,
302           strerror(errno), errno);
303     return -1;
304   }
305   return 0;
306 }
307 
clearDrmFB(hwc_drm_bo_t & bo)308 int DrmPresenter::clearDrmFB(hwc_drm_bo_t& bo) {
309   int ret = 0;
310   if (bo.fb_id) {
311     if (drmModeRmFB(mFd.get(), bo.fb_id)) {
312       ALOGE("%s: drmModeRmFB failed: %s (errno %d)", __FUNCTION__,
313             strerror(errno), errno);
314     }
315     ret = -1;
316   }
317   if (bo.gem_handles[0]) {
318     struct drm_gem_close gem_close = {};
319     gem_close.handle = bo.gem_handles[0];
320     if (drmIoctl(mFd.get(), DRM_IOCTL_GEM_CLOSE, &gem_close)) {
321       ALOGE("%s: DRM_IOCTL_GEM_CLOSE failed: %s (errno %d)", __FUNCTION__,
322             strerror(errno), errno);
323     }
324     ret = -1;
325   }
326   ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
327   return ret;
328 }
329 
handleHotplug()330 bool DrmPresenter::handleHotplug() {
331   std::vector<DrmConnector> oldConnectors(mConnectors);
332   {
333     AutoReadLock lock(mStateMutex);
334     oldConnectors.assign(mConnectors.begin(), mConnectors.end());
335   }
336   {
337     AutoWriteLock lock(mStateMutex);
338     resetDrmElementsLocked();
339     if (!initDrmElementsLocked()) {
340       ALOGE(
341           "%s: failed to initialize drm elements during hotplug. Displays may "
342           "not function correctly!",
343           __FUNCTION__);
344       return false;
345     }
346   }
347 
348   AutoReadLock lock(mStateMutex);
349   for (int i = 0; i < mConnectors.size(); i++) {
350     bool changed =
351         oldConnectors[i].dpiX != mConnectors[i].dpiX ||
352         oldConnectors[i].dpiY != mConnectors[i].dpiY ||
353         oldConnectors[i].connection != mConnectors[i].connection ||
354         oldConnectors[i].mMode.hdisplay != mConnectors[i].mMode.hdisplay ||
355         oldConnectors[i].mMode.vdisplay != mConnectors[i].mMode.vdisplay;
356     if (changed) {
357       if (i == 0) {
358         ALOGE(
359             "%s: Ignoring changes to display:0 which is not configurable by "
360             "multi-display interface.",
361             __FUNCTION__);
362         continue;
363       }
364 
365       bool connected =
366           mConnectors[i].connection == DRM_MODE_CONNECTED ? true : false;
367       if (mHotplugCallback) {
368         mHotplugCallback(connected, i, mConnectors[i].mMode.hdisplay,
369                          mConnectors[i].mMode.vdisplay, mConnectors[i].dpiX,
370                          mConnectors[i].dpiY,
371                          mConnectors[i].mRefreshRateAsInteger);
372       }
373     }
374   }
375   return true;
376 }
377 
flushToDisplay(int display,hwc_drm_bo_t & bo,int * outSyncFd)378 HWC2::Error DrmPresenter::flushToDisplay(int display, hwc_drm_bo_t& bo,
379                                          int* outSyncFd) {
380   AutoReadLock lock(mStateMutex);
381 
382   DrmConnector& connector = mConnectors[display];
383   DrmCrtc& crtc = mCrtcs[display];
384 
385   HWC2::Error error = HWC2::Error::None;
386 
387   *outSyncFd = -1;
388 
389   drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
390 
391   int ret;
392 
393   if (!crtc.mDidSetCrtc) {
394     DEBUG_LOG("%s: Setting crtc.\n", __FUNCTION__);
395     ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mActivePropertyId, 1);
396     if (ret < 0) {
397       ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
398     }
399     ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mModePropertyId,
400                                    connector.mModeBlobId);
401     if (ret < 0) {
402       ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
403     }
404     ret = drmModeAtomicAddProperty(pset, connector.mId,
405                                    connector.mCrtcPropertyId, crtc.mId);
406     if (ret < 0) {
407       ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
408     }
409 
410     crtc.mDidSetCrtc = true;
411   } else {
412     DEBUG_LOG("%s: Already set crtc\n", __FUNCTION__);
413   }
414 
415   uint64_t outSyncFdUint = (uint64_t)outSyncFd;
416 
417   ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mFencePropertyId,
418                                  outSyncFdUint);
419   if (ret < 0) {
420     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
421   }
422 
423   if (crtc.mPlaneId == -1) {
424     ALOGE("%s:%d: no plane available for crtc id %" PRIu32, __FUNCTION__,
425           __LINE__, crtc.mId);
426     return HWC2::Error::NoResources;
427   }
428 
429   DrmPlane& plane = mPlanes[crtc.mPlaneId];
430 
431   DEBUG_LOG("%s: set plane: plane id %d crtc id %d fbid %d bo w h %d %d\n",
432             __FUNCTION__, plane.mId, crtc.mId, bo.fb_id, bo.width, bo.height);
433 
434   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcPropertyId,
435                                  crtc.mId);
436   if (ret < 0) {
437     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
438   }
439   ret =
440       drmModeAtomicAddProperty(pset, plane.mId, plane.mFbPropertyId, bo.fb_id);
441   if (ret < 0) {
442     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
443   }
444   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcXPropertyId, 0);
445   if (ret < 0) {
446     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
447   }
448   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcYPropertyId, 0);
449   if (ret < 0) {
450     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
451   }
452   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcWPropertyId,
453                                  bo.width);
454   if (ret < 0) {
455     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
456   }
457   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcHPropertyId,
458                                  bo.height);
459   if (ret < 0) {
460     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
461   }
462   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcXPropertyId, 0);
463   if (ret < 0) {
464     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
465   }
466   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcYPropertyId, 0);
467   if (ret < 0) {
468     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
469   }
470   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcWPropertyId,
471                                  bo.width << 16);
472   if (ret < 0) {
473     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
474   }
475   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcHPropertyId,
476                                  bo.height << 16);
477   if (ret < 0) {
478     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
479   }
480 
481   uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
482   ret = drmModeAtomicCommit(mFd.get(), pset, flags, 0);
483 
484   if (ret) {
485     ALOGE("%s: Atomic commit failed with %d %d\n", __FUNCTION__, ret, errno);
486     error = HWC2::Error::NoResources;
487   }
488 
489   if (pset) {
490     drmModeAtomicFree(pset);
491   }
492 
493   DEBUG_LOG("%s: out fence: %d\n", __FUNCTION__, *outSyncFd);
494   return error;
495 }
496 
getEdid(uint32_t id)497 std::optional<std::vector<uint8_t>> DrmPresenter::getEdid(uint32_t id) {
498   AutoReadLock lock(mStateMutex);
499 
500   if (mConnectors[id].mEdidBlobId == -1) {
501     ALOGW("%s: EDID not supported", __func__);
502     return std::nullopt;
503   }
504   drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(mFd.get(),
505                                                        mConnectors[id].mEdidBlobId);
506   if (!blob) {
507     ALOGE("%s: fail to read EDID from DRM", __func__);
508     return std::nullopt;
509   }
510 
511   std::vector<uint8_t> edid;
512   uint8_t* start = static_cast<uint8_t*>(blob->data);
513   edid.insert(edid.begin(), start, start + blob->length);
514 
515   drmModeFreePropertyBlob(blob);
516 
517   return edid;
518 }
519 
DrmBuffer(const native_handle_t * handle,DrmPresenter & DrmPresenter)520 DrmBuffer::DrmBuffer(const native_handle_t* handle, DrmPresenter& DrmPresenter)
521     : mDrmPresenter(DrmPresenter), mBo({}) {
522   if (!convertBoInfo(handle)) {
523     mDrmPresenter.getDrmFB(mBo);
524   }
525 }
526 
~DrmBuffer()527 DrmBuffer::~DrmBuffer() { mDrmPresenter.clearDrmFB(mBo); }
528 
convertBoInfo(const native_handle_t * handle)529 int DrmBuffer::convertBoInfo(const native_handle_t* handle) {
530   cros_gralloc_handle* gr_handle = (cros_gralloc_handle*)handle;
531   if (!gr_handle) {
532     ALOGE("%s: Null buffer handle", __FUNCTION__);
533     return -1;
534   }
535   mBo.width = gr_handle->width;
536   mBo.height = gr_handle->height;
537   mBo.hal_format = gr_handle->droid_format;
538   mBo.format = gr_handle->format;
539   mBo.usage = gr_handle->usage;
540   mBo.prime_fds[0] = gr_handle->fds[0];
541   mBo.pitches[0] = gr_handle->strides[0];
542   return 0;
543 }
544 
flushToDisplay(int display,int * outFlushDoneSyncFd)545 HWC2::Error DrmBuffer::flushToDisplay(int display, int* outFlushDoneSyncFd) {
546   return mDrmPresenter.flushToDisplay(display, mBo, outFlushDoneSyncFd);
547 }
548 
DrmEventListener(DrmPresenter & presenter)549 DrmPresenter::DrmEventListener::DrmEventListener(DrmPresenter& presenter)
550     : mPresenter(presenter) {}
551 
~DrmEventListener()552 DrmPresenter::DrmEventListener::~DrmEventListener() {}
553 
init()554 bool DrmPresenter::DrmEventListener::init() {
555   mEventFd = android::base::unique_fd(
556       socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
557   if (!mEventFd.ok()) {
558     ALOGE("Failed to open uevent socket: %s", strerror(errno));
559     return false;
560   }
561   struct sockaddr_nl addr;
562   memset(&addr, 0, sizeof(addr));
563   addr.nl_family = AF_NETLINK;
564   addr.nl_pid = 0;
565   addr.nl_groups = 0xFFFFFFFF;
566 
567   int ret = bind(mEventFd, (struct sockaddr*)&addr, sizeof(addr));
568   if (ret) {
569     ALOGE("Failed to bind uevent socket: %s", strerror(errno));
570     return false;
571   }
572 
573   FD_ZERO(&mMonitoredFds);
574   FD_SET(mPresenter.mFd.get(), &mMonitoredFds);
575   FD_SET(mEventFd.get(), &mMonitoredFds);
576   mMaxFd = std::max(mPresenter.mFd.get(), mEventFd.get());
577 
578   return true;
579 }
580 
threadLoop()581 bool DrmPresenter::DrmEventListener::threadLoop() {
582   int ret;
583   do {
584     ret = select(mMaxFd + 1, &mMonitoredFds, NULL, NULL, NULL);
585   } while (ret == -1 && errno == EINTR);
586 
587   // if (FD_ISSET(mPresenter.mFd, &mFds)) {
588   //   TODO: handle drm related events
589   // }
590 
591   if (FD_ISSET(mEventFd.get(), &mMonitoredFds)) {
592     eventThreadLoop();
593   }
594   return true;
595 }
596 
eventThreadLoop()597 void DrmPresenter::DrmEventListener::eventThreadLoop() {
598   char buffer[1024];
599   int ret;
600 
601   struct timespec ts;
602   uint64_t timestamp = 0;
603   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
604   if (!ret) {
605     timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
606   } else {
607     ALOGE("Failed to get monotonic clock on hotplug %d", ret);
608   }
609 
610   while (true) {
611     ret = read(mEventFd.get(), &buffer, sizeof(buffer));
612     if (ret == 0) {
613       return;
614     } else if (ret < 0) {
615       ALOGE("Got error reading uevent %d", ret);
616       return;
617     }
618 
619     bool drmEvent = false, hotplugEvent = false;
620     for (int i = 0; i < ret;) {
621       char* event = buffer + i;
622       if (strcmp(event, "DEVTYPE=drm_minor")) {
623         drmEvent = true;
624       } else if (strcmp(event, "HOTPLUG=1")) {
625         hotplugEvent = true;
626       }
627 
628       i += strlen(event) + 1;
629     }
630 
631     if (drmEvent && hotplugEvent) {
632       processHotplug(timestamp);
633     }
634   }
635 }
636 
processHotplug(uint64_t timestamp)637 void DrmPresenter::DrmEventListener::processHotplug(uint64_t timestamp) {
638   ALOGD("DrmEventListener detected hotplug event %" PRIu64, timestamp);
639   mPresenter.handleHotplug();
640 }
641 }  // namespace android
642