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