• 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.mOutFencePtrPropertyId = 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, "IN_FENCE_FD")) {
147         plane.mInFenceFdPropertyId = planeProp->prop_id;
148       } else if (!strcmp(planeProp->name, "FB_ID")) {
149         plane.mFbPropertyId = planeProp->prop_id;
150       } else if (!strcmp(planeProp->name, "CRTC_X")) {
151         plane.mCrtcXPropertyId = planeProp->prop_id;
152       } else if (!strcmp(planeProp->name, "CRTC_Y")) {
153         plane.mCrtcYPropertyId = planeProp->prop_id;
154       } else if (!strcmp(planeProp->name, "CRTC_W")) {
155         plane.mCrtcWPropertyId = planeProp->prop_id;
156       } else if (!strcmp(planeProp->name, "CRTC_H")) {
157         plane.mCrtcHPropertyId = planeProp->prop_id;
158       } else if (!strcmp(planeProp->name, "SRC_X")) {
159         plane.mSrcXPropertyId = planeProp->prop_id;
160       } else if (!strcmp(planeProp->name, "SRC_Y")) {
161         plane.mSrcYPropertyId = planeProp->prop_id;
162       } else if (!strcmp(planeProp->name, "SRC_W")) {
163         plane.mSrcWPropertyId = planeProp->prop_id;
164       } else if (!strcmp(planeProp->name, "SRC_H")) {
165         plane.mSrcHPropertyId = planeProp->prop_id;
166       } else if (!strcmp(planeProp->name, "type")) {
167         plane.mTypePropertyId = planeProp->prop_id;
168         uint64_t type = planeProp->values[0];
169         switch (type) {
170           case DRM_PLANE_TYPE_OVERLAY:
171             plane.mType = type;
172             ALOGD("%s: plane %" PRIu32 " is DRM_PLANE_TYPE_OVERLAY",
173                   __FUNCTION__, plane.mId);
174             break;
175           case DRM_PLANE_TYPE_PRIMARY:
176             plane.mType = type;
177             ALOGD("%s: plane %" PRIu32 " is DRM_PLANE_TYPE_PRIMARY",
178                   __FUNCTION__, plane.mId);
179             break;
180           default:
181             break;
182         }
183       }
184 
185       drmModeFreeProperty(planeProp);
186     }
187 
188     drmModeFreeObjectProperties(planeProps);
189 
190     bool isPrimaryOrOverlay = plane.mType == DRM_PLANE_TYPE_OVERLAY ||
191                               plane.mType == DRM_PLANE_TYPE_PRIMARY;
192     if (isPrimaryOrOverlay) {
193       for (uint32_t j = 0; j < mCrtcs.size(); j++) {
194         if ((0x1 << j) & p->possible_crtcs) {
195           ALOGD("%s: plane %" PRIu32 " compatible with crtc mask %" PRIu32,
196                 __FUNCTION__, plane.mId, p->possible_crtcs);
197           if (mCrtcs[j].mPlaneId == -1) {
198             mCrtcs[j].mPlaneId = plane.mId;
199             ALOGD("%s: plane %" PRIu32 " associated with crtc %" PRIu32,
200                   __FUNCTION__, plane.mId, j);
201             break;
202           }
203         }
204       }
205     }
206 
207     drmModeFreePlane(p);
208     mPlanes[plane.mId] = plane;
209   }
210   drmModeFreePlaneResources(planeRes);
211 
212   for (uint32_t i = 0; i < res->count_connectors; ++i) {
213     DrmConnector connector = {};
214     connector.mId = res->connectors[i];
215 
216     {
217       drmModeObjectPropertiesPtr connectorProps = drmModeObjectGetProperties(
218           mFd.get(), connector.mId, DRM_MODE_OBJECT_CONNECTOR);
219 
220       for (uint32_t connectorPropIndex = 0;
221            connectorPropIndex < connectorProps->count_props;
222            ++connectorPropIndex) {
223         drmModePropertyPtr connectorProp = drmModeGetProperty(
224             mFd.get(), connectorProps->props[connectorPropIndex]);
225         if (!strcmp(connectorProp->name, "CRTC_ID")) {
226           connector.mCrtcPropertyId = connectorProp->prop_id;
227         } else if (!strcmp(connectorProp->name, "EDID")) {
228           connector.mEdidBlobId =
229               connectorProps->prop_values[connectorPropIndex];
230         }
231         drmModeFreeProperty(connectorProp);
232       }
233 
234       drmModeFreeObjectProperties(connectorProps);
235     }
236     {
237       drmModeConnector* c = drmModeGetConnector(mFd.get(), connector.mId);
238       if (c == nullptr) {
239         ALOGE("%s: Failed to get connector %" PRIu32 ": %d", __FUNCTION__,
240               connector.mId, errno);
241         return false;
242       }
243       connector.connection = c->connection;
244       if (c->count_modes > 0) {
245         memcpy(&connector.mMode, &c->modes[0], sizeof(drmModeModeInfo));
246         drmModeCreatePropertyBlob(mFd.get(), &connector.mMode,
247                                   sizeof(connector.mMode),
248                                   &connector.mModeBlobId);
249 
250         // Dots per 1000 inches
251         connector.dpiX =
252             c->mmWidth ? (c->modes[0].hdisplay * kUmPerInch) / (c->mmWidth)
253                        : -1;
254         // Dots per 1000 inches
255         connector.dpiY =
256             c->mmHeight ? (c->modes[0].vdisplay * kUmPerInch) / (c->mmHeight)
257                         : -1;
258       }
259       ALOGD("%s connector %" PRIu32 " dpiX %" PRIi32 " dpiY %" PRIi32
260             " connection %d",
261             __FUNCTION__, connector.mId, connector.dpiX, connector.dpiY,
262             connector.connection);
263 
264       drmModeFreeConnector(c);
265 
266       connector.mRefreshRateAsFloat =
267           1000.0f * connector.mMode.clock /
268           ((float)connector.mMode.vtotal * (float)connector.mMode.htotal);
269       connector.mRefreshRateAsInteger =
270           (uint32_t)(connector.mRefreshRateAsFloat + 0.5f);
271     }
272 
273     mConnectors.push_back(connector);
274   }
275 
276   drmModeFreeResources(res);
277   return true;
278 }
279 
resetDrmElementsLocked()280 void DrmPresenter::resetDrmElementsLocked() {
281   for (auto& c : mConnectors) {
282     if (c.mModeBlobId) {
283       if (drmModeDestroyPropertyBlob(mFd.get(), c.mModeBlobId)) {
284         ALOGE("%s: Error destroy PropertyBlob %" PRIu32, __func__,
285               c.mModeBlobId);
286       }
287     }
288   }
289   mConnectors.clear();
290   mCrtcs.clear();
291   mPlanes.clear();
292 }
293 
getDrmFB(hwc_drm_bo_t & bo)294 int DrmPresenter::getDrmFB(hwc_drm_bo_t& bo) {
295   int ret = drmPrimeFDToHandle(mFd.get(), bo.prime_fds[0], &bo.gem_handles[0]);
296   if (ret) {
297     ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__,
298           strerror(errno), errno);
299     return -1;
300   }
301   ret = drmModeAddFB2(mFd.get(), bo.width, bo.height, bo.format, bo.gem_handles,
302                       bo.pitches, bo.offsets, &bo.fb_id, 0);
303   if (ret) {
304     ALOGE("%s: drmModeAddFB2 failed: %s (errno %d)", __FUNCTION__,
305           strerror(errno), errno);
306     return -1;
307   }
308   return 0;
309 }
310 
clearDrmFB(hwc_drm_bo_t & bo)311 int DrmPresenter::clearDrmFB(hwc_drm_bo_t& bo) {
312   int ret = 0;
313   if (bo.fb_id) {
314     if (drmModeRmFB(mFd.get(), bo.fb_id)) {
315       ALOGE("%s: drmModeRmFB failed: %s (errno %d)", __FUNCTION__,
316             strerror(errno), errno);
317     }
318     ret = -1;
319   }
320   if (bo.gem_handles[0]) {
321     struct drm_gem_close gem_close = {};
322     gem_close.handle = bo.gem_handles[0];
323     if (drmIoctl(mFd.get(), DRM_IOCTL_GEM_CLOSE, &gem_close)) {
324       ALOGE("%s: DRM_IOCTL_GEM_CLOSE failed: %s (errno %d)", __FUNCTION__,
325             strerror(errno), errno);
326     }
327     ret = -1;
328   }
329   ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
330   return ret;
331 }
332 
handleHotplug()333 bool DrmPresenter::handleHotplug() {
334   std::vector<DrmConnector> oldConnectors(mConnectors);
335   {
336     AutoReadLock lock(mStateMutex);
337     oldConnectors.assign(mConnectors.begin(), mConnectors.end());
338   }
339   {
340     AutoWriteLock lock(mStateMutex);
341     resetDrmElementsLocked();
342     if (!initDrmElementsLocked()) {
343       ALOGE(
344           "%s: failed to initialize drm elements during hotplug. Displays may "
345           "not function correctly!",
346           __FUNCTION__);
347       return false;
348     }
349   }
350 
351   AutoReadLock lock(mStateMutex);
352   for (int i = 0; i < mConnectors.size(); i++) {
353     bool changed =
354         oldConnectors[i].dpiX != mConnectors[i].dpiX ||
355         oldConnectors[i].dpiY != mConnectors[i].dpiY ||
356         oldConnectors[i].connection != mConnectors[i].connection ||
357         oldConnectors[i].mMode.hdisplay != mConnectors[i].mMode.hdisplay ||
358         oldConnectors[i].mMode.vdisplay != mConnectors[i].mMode.vdisplay;
359     if (changed) {
360       if (i == 0) {
361         ALOGE(
362             "%s: Ignoring changes to display:0 which is not configurable by "
363             "multi-display interface.",
364             __FUNCTION__);
365         continue;
366       }
367 
368       bool connected =
369           mConnectors[i].connection == DRM_MODE_CONNECTED ? true : false;
370       if (mHotplugCallback) {
371         mHotplugCallback(connected, i, mConnectors[i].mMode.hdisplay,
372                          mConnectors[i].mMode.vdisplay, mConnectors[i].dpiX,
373                          mConnectors[i].dpiY,
374                          mConnectors[i].mRefreshRateAsInteger);
375       }
376     }
377   }
378   return true;
379 }
380 
flushToDisplay(int display,hwc_drm_bo_t & bo,base::borrowed_fd inSyncFd)381 std::tuple<HWC2::Error, base::unique_fd> DrmPresenter::flushToDisplay(
382     int display, hwc_drm_bo_t& bo, base::borrowed_fd inSyncFd) {
383   ATRACE_CALL();
384 
385   AutoReadLock lock(mStateMutex);
386 
387   DrmConnector& connector = mConnectors[display];
388   DrmCrtc& crtc = mCrtcs[display];
389 
390   HWC2::Error error = HWC2::Error::None;
391 
392   drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
393 
394   int ret;
395 
396   if (!crtc.mDidSetCrtc) {
397     DEBUG_LOG("%s: Setting crtc.\n", __FUNCTION__);
398     ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mActivePropertyId, 1);
399     if (ret < 0) {
400       ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
401     }
402     ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mModePropertyId,
403                                    connector.mModeBlobId);
404     if (ret < 0) {
405       ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
406     }
407     ret = drmModeAtomicAddProperty(pset, connector.mId,
408                                    connector.mCrtcPropertyId, crtc.mId);
409     if (ret < 0) {
410       ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
411     }
412 
413     crtc.mDidSetCrtc = true;
414   } else {
415     DEBUG_LOG("%s: Already set crtc\n", __FUNCTION__);
416   }
417 
418   int rawOutSyncFd;
419   uint64_t outSyncFdUint =
420       static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&rawOutSyncFd));
421 
422   ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mOutFencePtrPropertyId,
423                                  outSyncFdUint);
424   if (ret < 0) {
425     ALOGE("%s:%d: set OUT_FENCE_PTR failed %d errno %d\n", __FUNCTION__,
426           __LINE__, ret, errno);
427   }
428 
429   if (crtc.mPlaneId == -1) {
430     ALOGE("%s:%d: no plane available for crtc id %" PRIu32, __FUNCTION__,
431           __LINE__, crtc.mId);
432     return std::make_tuple(HWC2::Error::NoResources, base::unique_fd());
433   }
434 
435   DrmPlane& plane = mPlanes[crtc.mPlaneId];
436 
437   DEBUG_LOG("%s: set plane: plane id %d crtc id %d fbid %d bo w h %d %d\n",
438             __FUNCTION__, plane.mId, crtc.mId, bo.fb_id, bo.width, bo.height);
439 
440   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcPropertyId,
441                                  crtc.mId);
442   if (ret < 0) {
443     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
444   }
445   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mInFenceFdPropertyId,
446                                  inSyncFd.get());
447   if (ret < 0) {
448     ALOGE("%s:%d: set IN_FENCE_FD failed %d errno %d\n", __FUNCTION__, __LINE__,
449           ret, errno);
450   }
451   ret =
452       drmModeAtomicAddProperty(pset, plane.mId, plane.mFbPropertyId, bo.fb_id);
453   if (ret < 0) {
454     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
455   }
456   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcXPropertyId, 0);
457   if (ret < 0) {
458     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
459   }
460   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcYPropertyId, 0);
461   if (ret < 0) {
462     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
463   }
464   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcWPropertyId,
465                                  bo.width);
466   if (ret < 0) {
467     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
468   }
469   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcHPropertyId,
470                                  bo.height);
471   if (ret < 0) {
472     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
473   }
474   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcXPropertyId, 0);
475   if (ret < 0) {
476     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
477   }
478   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcYPropertyId, 0);
479   if (ret < 0) {
480     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
481   }
482   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcWPropertyId,
483                                  bo.width << 16);
484   if (ret < 0) {
485     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
486   }
487   ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcHPropertyId,
488                                  bo.height << 16);
489   if (ret < 0) {
490     ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
491   }
492 
493   uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
494   ret = drmModeAtomicCommit(mFd.get(), pset, flags, 0);
495 
496   if (ret) {
497     ALOGE("%s: Atomic commit failed with %d %d\n", __FUNCTION__, ret, errno);
498     error = HWC2::Error::NoResources;
499   }
500   base::unique_fd outSyncFd(rawOutSyncFd);
501 
502   if (pset) {
503     drmModeAtomicFree(pset);
504   }
505 
506   DEBUG_LOG("%s: out fence: %d\n", __FUNCTION__, outSyncFd.get());
507   return std::make_tuple(error, std::move(outSyncFd));
508 }
509 
getEdid(uint32_t id)510 std::optional<std::vector<uint8_t>> DrmPresenter::getEdid(uint32_t id) {
511   AutoReadLock lock(mStateMutex);
512 
513   if (mConnectors[id].mEdidBlobId == -1) {
514     ALOGW("%s: EDID not supported", __func__);
515     return std::nullopt;
516   }
517   drmModePropertyBlobPtr blob =
518       drmModeGetPropertyBlob(mFd.get(), mConnectors[id].mEdidBlobId);
519   if (!blob) {
520     ALOGE("%s: fail to read EDID from DRM", __func__);
521     return std::nullopt;
522   }
523 
524   std::vector<uint8_t> edid;
525   uint8_t* start = static_cast<uint8_t*>(blob->data);
526   edid.insert(edid.begin(), start, start + blob->length);
527 
528   drmModeFreePropertyBlob(blob);
529 
530   return edid;
531 }
532 
DrmBuffer(const native_handle_t * handle,DrmPresenter * drmPresenter)533 DrmBuffer::DrmBuffer(const native_handle_t* handle, DrmPresenter* drmPresenter)
534     : mDrmPresenter(drmPresenter), mBo({}) {
535   if (!convertBoInfo(handle)) {
536     mDrmPresenter->getDrmFB(mBo);
537   }
538 }
539 
~DrmBuffer()540 DrmBuffer::~DrmBuffer() { mDrmPresenter->clearDrmFB(mBo); }
541 
convertBoInfo(const native_handle_t * handle)542 int DrmBuffer::convertBoInfo(const native_handle_t* handle) {
543   cros_gralloc_handle* gr_handle = (cros_gralloc_handle*)handle;
544   if (!gr_handle) {
545     ALOGE("%s: Null buffer handle", __FUNCTION__);
546     return -1;
547   }
548   mBo.width = gr_handle->width;
549   mBo.height = gr_handle->height;
550   mBo.hal_format = gr_handle->droid_format;
551   mBo.format = gr_handle->format;
552   mBo.usage = gr_handle->usage;
553   mBo.prime_fds[0] = gr_handle->fds[0];
554   mBo.pitches[0] = gr_handle->strides[0];
555   return 0;
556 }
557 
flushToDisplay(int display,base::borrowed_fd inWaitSyncFd)558 std::tuple<HWC2::Error, base::unique_fd> DrmBuffer::flushToDisplay(
559     int display, base::borrowed_fd inWaitSyncFd) {
560   return mDrmPresenter->flushToDisplay(display, mBo, inWaitSyncFd);
561 }
562 
DrmEventListener(DrmPresenter & presenter)563 DrmPresenter::DrmEventListener::DrmEventListener(DrmPresenter& presenter)
564     : mPresenter(presenter) {}
565 
~DrmEventListener()566 DrmPresenter::DrmEventListener::~DrmEventListener() {}
567 
init()568 bool DrmPresenter::DrmEventListener::init() {
569   mEventFd = android::base::unique_fd(
570       socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
571   if (!mEventFd.ok()) {
572     ALOGE("Failed to open uevent socket: %s", strerror(errno));
573     return false;
574   }
575   struct sockaddr_nl addr;
576   memset(&addr, 0, sizeof(addr));
577   addr.nl_family = AF_NETLINK;
578   addr.nl_pid = 0;
579   addr.nl_groups = 0xFFFFFFFF;
580 
581   int ret = bind(mEventFd, (struct sockaddr*)&addr, sizeof(addr));
582   if (ret) {
583     ALOGE("Failed to bind uevent socket: %s", strerror(errno));
584     return false;
585   }
586 
587   FD_ZERO(&mMonitoredFds);
588   FD_SET(mPresenter.mFd.get(), &mMonitoredFds);
589   FD_SET(mEventFd.get(), &mMonitoredFds);
590   mMaxFd = std::max(mPresenter.mFd.get(), mEventFd.get());
591 
592   return true;
593 }
594 
threadLoop()595 bool DrmPresenter::DrmEventListener::threadLoop() {
596   int ret;
597   do {
598     ret = select(mMaxFd + 1, &mMonitoredFds, NULL, NULL, NULL);
599   } while (ret == -1 && errno == EINTR);
600 
601   // if (FD_ISSET(mPresenter.mFd, &mFds)) {
602   //   TODO: handle drm related events
603   // }
604 
605   if (FD_ISSET(mEventFd.get(), &mMonitoredFds)) {
606     eventThreadLoop();
607   }
608   return true;
609 }
610 
eventThreadLoop()611 void DrmPresenter::DrmEventListener::eventThreadLoop() {
612   char buffer[1024];
613   int ret;
614 
615   struct timespec ts;
616   uint64_t timestamp = 0;
617   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
618   if (!ret) {
619     timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
620   } else {
621     ALOGE("Failed to get monotonic clock on hotplug %d", ret);
622   }
623 
624   while (true) {
625     ret = read(mEventFd.get(), &buffer, sizeof(buffer));
626     if (ret == 0) {
627       return;
628     } else if (ret < 0) {
629       ALOGE("Got error reading uevent %d", ret);
630       return;
631     }
632 
633     bool drmEvent = false, hotplugEvent = false;
634     for (int i = 0; i < ret;) {
635       char* event = buffer + i;
636       if (strcmp(event, "DEVTYPE=drm_minor")) {
637         drmEvent = true;
638       } else if (strcmp(event, "HOTPLUG=1")) {
639         hotplugEvent = true;
640       }
641 
642       i += strlen(event) + 1;
643     }
644 
645     if (drmEvent && hotplugEvent) {
646       processHotplug(timestamp);
647     }
648   }
649 }
650 
processHotplug(uint64_t timestamp)651 void DrmPresenter::DrmEventListener::processHotplug(uint64_t timestamp) {
652   ALOGD("DrmEventListener detected hotplug event %" PRIu64, timestamp);
653   mPresenter.handleHotplug();
654 }
655 }  // namespace android
656