1 /*
2 * Copyright (C) 2023 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 ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
18
19 #include "HistogramDevice.h"
20
21 #include <drm/samsung_drm.h>
22
23 #include <sstream>
24 #include <string>
25
26 #include "ExynosDisplayDrmInterface.h"
27 #include "ExynosHWCHelper.h"
28 #include "android-base/macros.h"
29
30 /**
31 * histogramOnBinderDied
32 *
33 * The binderdied callback function which is registered in registerHistogram and would trigger
34 * unregisterHistogram to cleanup the resources.
35 *
36 * @cookie pointer to the TokenInfo of the binder object.
37 */
histogramOnBinderDied(void * cookie)38 static void histogramOnBinderDied(void* cookie) {
39 HistogramDevice::HistogramErrorCode histogramErrorCode;
40 HistogramDevice::TokenInfo* tokenInfo = (HistogramDevice::TokenInfo*)cookie;
41 ATRACE_NAME(String8::format("%s pid=%d", __func__, tokenInfo->mPid).c_str());
42 ALOGI("%s: process %d with token(%p) is died", __func__, tokenInfo->mPid,
43 tokenInfo->mToken.get());
44
45 // release the histogram resources
46 tokenInfo->mHistogramDevice->unregisterHistogram(tokenInfo->mToken, &histogramErrorCode);
47 if (histogramErrorCode != HistogramDevice::HistogramErrorCode::NONE) {
48 ALOGW("%s: failed to unregisterHistogram, error(%s)", __func__,
49 aidl::com::google::hardware::pixel::display::toString(histogramErrorCode).c_str());
50 }
51 }
52
HistogramDevice(ExynosDisplay * const display,const uint8_t channelCount,const std::vector<uint8_t> reservedChannels)53 HistogramDevice::HistogramDevice(ExynosDisplay* const display, const uint8_t channelCount,
54 const std::vector<uint8_t> reservedChannels)
55 : mDisplay(display) {
56 // TODO: b/295786065 - Get available channels from crtc property.
57 initChannels(channelCount, reservedChannels);
58
59 // Create the death recipient which will be deleted in the destructor
60 mDeathRecipient = AIBinder_DeathRecipient_new(histogramOnBinderDied);
61 }
62
~HistogramDevice()63 HistogramDevice::~HistogramDevice() {
64 if (mDeathRecipient) {
65 AIBinder_DeathRecipient_delete(mDeathRecipient);
66 }
67 }
68
initDrm(DrmDevice & device,const DrmCrtc & crtc)69 void HistogramDevice::initDrm(DrmDevice& device, const DrmCrtc& crtc) {
70 // TODO: b/295786065 - Get available channels from crtc property.
71 ATRACE_NAME("HistogramDevice::initDrm");
72
73 {
74 std::unique_lock<std::mutex> lock(mInitDrmDoneMutex);
75 ::android::base::ScopedLockAssertion lock_assertion(mInitDrmDoneMutex);
76 ATRACE_NAME("mInitDrmDoneMutex");
77 if (mInitDrmDone) {
78 HIST_LOG(W, "should be called only once, ignore!");
79 return;
80 }
81
82 initHistogramCapability(crtc.histogram_channel_property(0).id() != 0);
83 mDrmDevice = &device;
84 mInitDrmDone = true;
85 mInitDrmDone_cv.notify_all();
86 }
87
88 // print the histogram capability
89 String8 logString;
90 dumpHistogramCapability(logString);
91 ALOGI("%s", logString.c_str());
92 HIST_LOG(D, "successfully");
93 }
94
waitInitDrmDone() const95 bool HistogramDevice::waitInitDrmDone() const {
96 ATRACE_CALL();
97 std::unique_lock<std::mutex> lock(mInitDrmDoneMutex);
98 ::android::base::ScopedLockAssertion lock_assertion(mInitDrmDoneMutex);
99
100 mInitDrmDone_cv.wait_for(lock, std::chrono::milliseconds(50), [this]() -> bool {
101 ::android::base::ScopedLockAssertion lock_assertion(mInitDrmDoneMutex);
102 return mInitDrmDone;
103 });
104
105 return mInitDrmDone;
106 }
107
getHistogramCapability(HistogramCapability * histogramCapability) const108 ndk::ScopedAStatus HistogramDevice::getHistogramCapability(
109 HistogramCapability* histogramCapability) const {
110 ATRACE_CALL();
111
112 if (!histogramCapability) {
113 HIST_LOG(E, "binder error, histogramCapability is nullptr");
114 return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
115 }
116
117 if (waitInitDrmDone() == false) {
118 HIST_LOG(E, "initDrm is not completed yet");
119 return errorToStatus(HistogramErrorCode::TRY_AGAIN);
120 }
121
122 std::shared_lock lock(mHistogramCapabilityMutex);
123 *histogramCapability = mHistogramCapability;
124
125 return ndk::ScopedAStatus::ok();
126 }
127
128 #if defined(EXYNOS_HISTOGRAM_CHANNEL_REQUEST)
registerHistogram(const ndk::SpAIBinder & token,const HistogramConfig & histogramConfig,HistogramErrorCode * histogramErrorCode)129 ndk::ScopedAStatus HistogramDevice::registerHistogram(const ndk::SpAIBinder& token,
130 const HistogramConfig& histogramConfig,
131 HistogramErrorCode* histogramErrorCode) {
132 ATRACE_CALL();
133
134 if (waitInitDrmDone() == false) {
135 HIST_LOG(E, "initDrm is not completed yet");
136 // TODO: b/323158344 - add retry error in HistogramErrorCode and return here.
137 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
138 }
139
140 {
141 std::shared_lock lock(mHistogramCapabilityMutex);
142 if (UNLIKELY(!mHistogramCapability.supportMultiChannel)) {
143 HIST_LOG(E, "multi-channel interface is not supported");
144 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
145 }
146 }
147
148 ndk::ScopedAStatus binderStatus =
149 validateHistogramRequest(token, histogramConfig, histogramErrorCode);
150 if (!binderStatus.isOk() || *histogramErrorCode != HistogramErrorCode::NONE) {
151 HIST_LOG(E, "validateHistogramRequest failed");
152 return binderStatus;
153 }
154
155 // Create the histogram config blob if possible, early creation can reduce critical section
156 int ret;
157 const auto [displayActiveH, displayActiveV] = snapDisplayActiveSize();
158 std::shared_ptr<PropertyBlob> drmConfigBlob;
159 if ((ret = createDrmConfigBlob(histogramConfig, displayActiveH, displayActiveV, drmConfigBlob)))
160 HIST_LOG(D, "createDrmConfigBlob failed, skip creation, ret(%d)", ret);
161
162 bool needRefresh = false;
163
164 {
165 // Insert new client's token into mTokenInfoMap
166 SCOPED_HIST_LOCK(mHistogramMutex);
167 auto [it, emplaceResult] =
168 mTokenInfoMap.try_emplace(token.get(), this, token, AIBinder_getCallingPid());
169 if (!emplaceResult) {
170 HIST_LOG(E, "BAD_TOKEN, token(%p) is already registered", token.get());
171 *histogramErrorCode = HistogramErrorCode::BAD_TOKEN;
172 return ndk::ScopedAStatus::ok();
173 }
174 auto tokenInfo = &it->second;
175
176 /* In previous design, histogram client is attached to the histogram channel directly. Now
177 * we use struct ConfigInfo to maintain the config metadata. We can benefit from this
178 * design:
179 * 1. More elegantly to change the applied config of the histogram channels (basics of
180 * virtualization).
181 * 2. We may be able to share the same struct ConfigInfo for different histogram clients
182 * when the histogramConfigs via registerHistogram are the same. */
183 auto& configInfo = tokenInfo->mConfigInfo;
184 replaceConfigInfo(configInfo, &histogramConfig);
185
186 // Attach the histogram drmConfigBlob to the configInfo
187 if (drmConfigBlob)
188 configInfo->mBlobsList.emplace_front(displayActiveH, displayActiveV, drmConfigBlob);
189
190 needRefresh = scheduler();
191
192 /* link the binder object (token) to the death recipient. When the binder object is
193 * destructed, the callback function histogramOnBinderDied can release the histogram
194 * resources automatically. */
195 binder_status_t status;
196 if ((status = AIBinder_linkToDeath(token.get(), mDeathRecipient, tokenInfo))) {
197 /* Not return error due to the AIBinder_linkToDeath because histogram function can
198 * still work */
199 HIST_CH_LOG(E, configInfo->mChannelId, "token(%p): AIBinder_linkToDeath error, ret(%d)",
200 token.get(), status);
201 }
202 }
203
204 if (needRefresh) {
205 ATRACE_NAME("HistogramOnRefresh");
206 mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
207 }
208
209 HIST_LOG(D, "register client successfully");
210
211 return ndk::ScopedAStatus::ok();
212 }
213 #else
registerHistogram(const ndk::SpAIBinder & token,const HistogramConfig & histogramConfig,HistogramErrorCode * histogramErrorCode)214 ndk::ScopedAStatus HistogramDevice::registerHistogram(const ndk::SpAIBinder& token,
215 const HistogramConfig& histogramConfig,
216 HistogramErrorCode* histogramErrorCode) {
217 ATRACE_CALL();
218 HIST_LOG(E, "multi-channel interface is not supported");
219 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
220 }
221 #endif
222
queryHistogram(const ndk::SpAIBinder & token,std::vector<char16_t> * histogramBuffer,HistogramErrorCode * histogramErrorCode)223 ndk::ScopedAStatus HistogramDevice::queryHistogram(const ndk::SpAIBinder& token,
224 std::vector<char16_t>* histogramBuffer,
225 HistogramErrorCode* histogramErrorCode) {
226 ATRACE_CALL();
227
228 {
229 std::shared_lock lock(mHistogramCapabilityMutex);
230 if (UNLIKELY(!mHistogramCapability.supportMultiChannel)) {
231 HIST_LOG(E, "multi-channel interface is not supported");
232 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
233 }
234 }
235
236 // validate the argument (histogramBuffer)
237 if (!histogramBuffer) {
238 HIST_LOG(E, "binder error, histogramBuffer is nullptr");
239 return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
240 }
241
242 // validate the argument (histogramErrorCode)
243 if (!histogramErrorCode) {
244 HIST_LOG(E, "binder error, histogramErrorCode is nullptr");
245 return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
246 }
247
248 getHistogramData(token, histogramBuffer, histogramErrorCode);
249
250 return ndk::ScopedAStatus::ok();
251 }
252
reconfigHistogram(const ndk::SpAIBinder & token,const HistogramConfig & histogramConfig,HistogramErrorCode * histogramErrorCode)253 ndk::ScopedAStatus HistogramDevice::reconfigHistogram(const ndk::SpAIBinder& token,
254 const HistogramConfig& histogramConfig,
255 HistogramErrorCode* histogramErrorCode) {
256 ATRACE_CALL();
257
258 {
259 std::shared_lock lock(mHistogramCapabilityMutex);
260 if (UNLIKELY(!mHistogramCapability.supportMultiChannel)) {
261 HIST_LOG(E, "multi-channel interface is not supported");
262 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
263 }
264 }
265
266 ndk::ScopedAStatus binderStatus =
267 validateHistogramRequest(token, histogramConfig, histogramErrorCode);
268 if (!binderStatus.isOk() || *histogramErrorCode != HistogramErrorCode::NONE) {
269 HIST_LOG(E, "validateHistogramRequest failed");
270 return binderStatus;
271 }
272
273 // Create the histogram config blob if possible, early creation can reduce critical section
274 int ret;
275 const auto [displayActiveH, displayActiveV] = snapDisplayActiveSize();
276 std::shared_ptr<PropertyBlob> drmConfigBlob;
277 if ((ret = createDrmConfigBlob(histogramConfig, displayActiveH, displayActiveV, drmConfigBlob)))
278 HIST_LOG(D, "createDrmConfigBlob failed, skip creation, ret(%d)", ret);
279
280 bool needRefresh = false;
281
282 {
283 // Search the registered tokenInfo
284 TokenInfo* tokenInfo = nullptr;
285 SCOPED_HIST_LOCK(mHistogramMutex);
286 if ((*histogramErrorCode = searchTokenInfo(token, tokenInfo)) != HistogramErrorCode::NONE) {
287 HIST_LOG(E, "searchTokenInfo failed, error(%s)",
288 aidl::com::google::hardware::pixel::display::toString(*histogramErrorCode)
289 .c_str());
290 return ndk::ScopedAStatus::ok();
291 }
292
293 // Change the histogram configInfo
294 auto& configInfo = tokenInfo->mConfigInfo;
295 replaceConfigInfo(configInfo, &histogramConfig);
296
297 // Attach the histogram drmConfigBlob to the configInfo
298 if (drmConfigBlob)
299 configInfo->mBlobsList.emplace_front(displayActiveH, displayActiveV, drmConfigBlob);
300
301 if (configInfo->mStatus == ConfigInfo::Status_t::HAS_CHANNEL_ASSIGNED) needRefresh = true;
302 }
303
304 if (needRefresh) {
305 ATRACE_NAME("HistogramOnRefresh");
306 mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
307 }
308
309 return ndk::ScopedAStatus::ok();
310 }
311
unregisterHistogram(const ndk::SpAIBinder & token,HistogramErrorCode * histogramErrorCode)312 ndk::ScopedAStatus HistogramDevice::unregisterHistogram(const ndk::SpAIBinder& token,
313 HistogramErrorCode* histogramErrorCode) {
314 ATRACE_CALL();
315
316 {
317 std::shared_lock lock(mHistogramCapabilityMutex);
318 if (UNLIKELY(!mHistogramCapability.supportMultiChannel)) {
319 HIST_LOG(E, "multi-channel interface is not supported");
320 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
321 }
322 }
323
324 // validate the argument (histogramErrorCode)
325 if (!histogramErrorCode) {
326 HIST_LOG(E, "binder error, histogramErrorCode is nullptr");
327 return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
328 }
329
330 // default histogramErrorCode: no error
331 *histogramErrorCode = HistogramErrorCode::NONE;
332
333 bool needRefresh = false;
334
335 {
336 // Search the registered tokenInfo
337 TokenInfo* tokenInfo = nullptr;
338 SCOPED_HIST_LOCK(mHistogramMutex);
339 if ((*histogramErrorCode = searchTokenInfo(token, tokenInfo)) != HistogramErrorCode::NONE) {
340 HIST_LOG(E, "searchTokenInfo failed, error(%s)",
341 aidl::com::google::hardware::pixel::display::toString(*histogramErrorCode)
342 .c_str());
343 return ndk::ScopedAStatus::ok();
344 }
345
346 // Clear the histogram configInfo
347 replaceConfigInfo(tokenInfo->mConfigInfo, nullptr);
348
349 /*
350 * If AIBinder is alive, the unregisterHistogram is triggered from the histogram client, and
351 * we need to unlink the binder object from death notification. If AIBinder is already dead,
352 * the unregisterHistogram is triggered from binderdied callback, no need to unlink here.
353 */
354 if (LIKELY(AIBinder_isAlive(token.get()))) {
355 binder_status_t status;
356 if ((status = AIBinder_unlinkToDeath(token.get(), mDeathRecipient, tokenInfo))) {
357 // Not return error due to the AIBinder_unlinkToDeath
358 HIST_LOG(E, "AIBinder_unlinkToDeath error for token(%p), ret(%d)", token.get(),
359 status);
360 }
361 }
362
363 // Delete the corresponding TokenInfo after the binder object is already unlinked.
364 mTokenInfoMap.erase(token.get());
365 tokenInfo = nullptr;
366
367 needRefresh = scheduler();
368 }
369
370 if (needRefresh) {
371 ATRACE_NAME("HistogramOnRefresh");
372 mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
373 }
374
375 HIST_LOG(D, "unregister client successfully");
376
377 return ndk::ScopedAStatus::ok();
378 }
379
_handleDrmEvent(void * event,uint32_t blobId,char16_t * buffer)380 void HistogramDevice::_handleDrmEvent(void* event, uint32_t blobId, char16_t* buffer) {
381 ATRACE_NAME(String8::format("handleHistogramEvent(blob#%u)", blobId).c_str());
382
383 std::shared_ptr<BlobIdData> blobIdData;
384 searchOrCreateBlobIdData(blobId, false, blobIdData);
385 if (!blobIdData) {
386 HIST_BLOB_LOG(W, blobId, "no condition var allocated, ignore the event(%p)", event);
387 return;
388 }
389
390 std::unique_lock<std::mutex> lock(blobIdData->mDataCollectingMutex);
391 ::android::base::ScopedLockAssertion lock_assertion(blobIdData->mDataCollectingMutex);
392 ATRACE_NAME(String8::format("mDataCollectingMutex(blob#%u)", blobId));
393 // Check if the histogram blob is collecting the histogram data
394 if (UNLIKELY(blobIdData->mCollectStatus == CollectStatus_t::NOT_STARTED)) {
395 HIST_BLOB_LOG(W, blobId, "ignore the event(%p), collectStatus is NOT_STARTED", event);
396 } else {
397 std::memcpy(blobIdData->mData, buffer, HISTOGRAM_BIN_COUNT * sizeof(char16_t));
398 blobIdData->mCollectStatus = CollectStatus_t::COLLECTED;
399 blobIdData->mDataCollecting_cv.notify_all();
400 }
401 }
402
handleDrmEvent(void * event)403 void HistogramDevice::handleDrmEvent(void* event) {
404 int ret = NO_ERROR;
405 uint32_t blobId = 0, channelId = 0;
406 char16_t* buffer;
407
408 if ((ret = parseDrmEvent(event, channelId, buffer))) {
409 HIST_LOG(E, "parseDrmEvent failed, ret(%d)", ret);
410 return;
411 }
412
413 // For the old kernel without blob id query supports, fake the blobId with channelId.
414 // In this hack way can prevent some duplicate codes just for channel id as well.
415 // In the future, all kernel will support blob id query. And can remove the hack.
416 blobId = channelId;
417 _handleDrmEvent(event, blobId, buffer);
418 }
419
handleContextDrmEvent(void * event)420 void HistogramDevice::handleContextDrmEvent(void* event) {
421 int ret = NO_ERROR;
422 uint32_t blobId = 0;
423 char16_t* buffer;
424
425 if ((ret = parseContextDrmEvent(event, blobId, buffer))) {
426 HIST_LOG(E, "parseContextDrmEvent failed, ret(%d)", ret);
427 return;
428 }
429
430 _handleDrmEvent(event, blobId, buffer);
431 }
432
prepareAtomicCommit(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)433 void HistogramDevice::prepareAtomicCommit(ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq) {
434 {
435 std::shared_lock lock(mHistogramCapabilityMutex);
436 // Skip multi channel histogram commit if not supported.
437 if (!mHistogramCapability.supportMultiChannel) return;
438 }
439
440 ATRACE_NAME("HistogramAtomicCommit");
441
442 ExynosDisplayDrmInterface* moduleDisplayInterface =
443 static_cast<ExynosDisplayDrmInterface*>(mDisplay->mDisplayInterface.get());
444 if (!moduleDisplayInterface) {
445 HIST_LOG(E, "failed to send atomic commit, moduleDisplayInterface is NULL");
446 return;
447 }
448
449 const auto [displayActiveH, displayActiveV] = snapDisplayActiveSize();
450 SCOPED_HIST_LOCK(mHistogramMutex);
451
452 // Loop through every used channel and set config blob if needed.
453 for (auto it = mUsedChannels.begin(); it != mUsedChannels.end();) {
454 uint8_t channelId = *it;
455 ChannelInfo& channel = mChannels[channelId];
456
457 if (channel.mStatus == ChannelStatus_t::CONFIG_COMMITTED ||
458 channel.mStatus == ChannelStatus_t::CONFIG_PENDING) {
459 std::shared_ptr<ConfigInfo> configInfo = channel.mConfigInfo.lock();
460 if (!configInfo) {
461 HIST_CH_LOG(E, channelId, "expired configInfo, review code!");
462 it = cleanupChannelInfo(channelId);
463 continue;
464 }
465 setChannelConfigBlob(drmReq, channelId, moduleDisplayInterface, displayActiveH,
466 displayActiveV, configInfo);
467 }
468
469 ++it;
470 }
471
472 // Loop through every free channels and disable channel if needed
473 for (auto it = mFreeChannels.begin(); it != mFreeChannels.end(); ++it) {
474 uint8_t channelId = *it;
475 ChannelInfo& channel = mChannels[channelId];
476 if (channel.mStatus == ChannelStatus_t::DISABLE_PENDING)
477 clearChannelConfigBlob(drmReq, channelId, moduleDisplayInterface);
478 }
479 }
480
postAtomicCommit()481 void HistogramDevice::postAtomicCommit() {
482 {
483 std::shared_lock lock(mHistogramCapabilityMutex);
484 // Skip multi channel histogram commit if not supported.
485 if (!mHistogramCapability.supportMultiChannel) return;
486 }
487
488 ATRACE_CALL();
489
490 {
491 SCOPED_HIST_LOCK(mHistogramMutex);
492
493 // Atomic commit is success, loop through every channel and update the channel status
494 for (uint8_t channelId = 0; channelId < mChannels.size(); ++channelId) {
495 ChannelInfo& channel = mChannels[channelId];
496
497 switch (channel.mStatus) {
498 case ChannelStatus_t::CONFIG_BLOB_ADDED:
499 channel.mStatus = ChannelStatus_t::CONFIG_COMMITTED;
500 break;
501 case ChannelStatus_t::DISABLE_BLOB_ADDED:
502 channel.mStatus = ChannelStatus_t::DISABLED;
503 break;
504 default:
505 break;
506 }
507 }
508 }
509
510 postAtomicCommitCleanup();
511 }
512
dump(String8 & result) const513 void HistogramDevice::dump(String8& result) const {
514 {
515 std::shared_lock lock(mHistogramCapabilityMutex);
516 // Do not dump the Histogram Device if it is not supported.
517 if (!mHistogramCapability.supportMultiChannel) {
518 return;
519 }
520 }
521
522 ATRACE_NAME("HistogramDump");
523
524 // print the histogram capability
525 dumpHistogramCapability(result);
526 result.append("\n");
527
528 SCOPED_HIST_LOCK(mHistogramMutex);
529
530 // print the tokens and the requested configs
531 for (const auto& [_, tokenInfo] : mTokenInfoMap) {
532 tokenInfo.dump(result);
533 if (tokenInfo.mConfigInfo) {
534 tokenInfo.mConfigInfo->dump(result, "\t");
535 }
536 }
537 dumpInternalConfigs(result);
538 result.append("\n");
539
540 // print the histogram channel info
541 result.append("Histogram channel info (applied to kernel):\n");
542 for (uint8_t channelId = 0; channelId < mChannels.size(); ++channelId) {
543 // TODO: b/294489887 - Use buildForMiniDump can eliminate the redundant rows.
544 TableBuilder tb;
545 dumpChannel(tb, channelId);
546 result.append(tb.build().c_str());
547 }
548 result.append("\n");
549
550 // print the inactive list
551 result.append("Histogram inactive list:");
552 if (mInactiveConfigItList.empty()) {
553 result.append(" none\n");
554 } else {
555 result.append("\n");
556 int i = 1;
557 for (const auto& configInfo : mInactiveConfigItList)
558 result.appendFormat("\t%d. configInfo: %p\n", i++, configInfo.lock().get());
559 }
560 result.append("\n");
561 result.append("-----End of Histogram dump-----\n");
562 }
563
initChannels(const uint8_t channelCount,const std::vector<uint8_t> & reservedChannels)564 void HistogramDevice::initChannels(const uint8_t channelCount,
565 const std::vector<uint8_t>& reservedChannels) {
566 ATRACE_CALL();
567 HIST_LOG(I, "init with %u channels", channelCount);
568
569 SCOPED_HIST_LOCK(mHistogramMutex);
570 mChannels.resize(channelCount);
571
572 for (const uint8_t reservedChannelId : reservedChannels) {
573 if (reservedChannelId < mChannels.size()) {
574 mChannels[reservedChannelId].mStatus = ChannelStatus_t::RESERVED;
575 } else {
576 HIST_CH_LOG(W, reservedChannelId,
577 "invalid channel cannot be reserved (channelCount: %u)", channelCount);
578 }
579 }
580
581 for (uint8_t channelId = 0; channelId < channelCount; ++channelId) {
582 if (mChannels[channelId].mStatus == ChannelStatus_t::RESERVED) {
583 HIST_CH_LOG(D, channelId, "channel reserved for driver");
584 continue;
585 }
586
587 mFreeChannels.push_back(channelId);
588 }
589 }
590
initHistogramCapability(const bool supportMultiChannel)591 void HistogramDevice::initHistogramCapability(const bool supportMultiChannel) {
592 ATRACE_CALL();
593 uint8_t channelCount = 0;
594 {
595 SCOPED_HIST_LOCK(mHistogramMutex);
596 channelCount = mChannels.size();
597 }
598
599 ExynosDisplayDrmInterface* moduleDisplayInterface =
600 static_cast<ExynosDisplayDrmInterface*>(mDisplay->mDisplayInterface.get());
601
602 SCOPED_HIST_LOCK(mHistogramCapabilityMutex);
603 if (!moduleDisplayInterface) {
604 HIST_LOG(E, "failed to get panel full resolution, moduleDisplayInterface is NULL");
605 mHistogramCapability.fullResolutionWidth = 0;
606 mHistogramCapability.fullResolutionHeight = 0;
607 } else {
608 mHistogramCapability.fullResolutionWidth =
609 moduleDisplayInterface->getPanelFullResolutionHSize();
610 mHistogramCapability.fullResolutionHeight =
611 moduleDisplayInterface->getPanelFullResolutionVSize();
612 }
613 mHistogramCapability.channelCount = channelCount;
614 mHistogramCapability.supportMultiChannel = supportMultiChannel;
615 mHistogramCapability.supportSamplePosList.push_back(HistogramSamplePos::POST_POSTPROC);
616 mHistogramCapability.supportBlockingRoi = false;
617 mHistogramCapability.supportQueryOpr = false;
618 initPlatformHistogramCapability();
619 }
620
replaceConfigInfo(std::shared_ptr<ConfigInfo> & configInfo,const HistogramConfig * histogramConfig)621 void HistogramDevice::replaceConfigInfo(std::shared_ptr<ConfigInfo>& configInfo,
622 const HistogramConfig* histogramConfig) {
623 ATRACE_CALL();
624
625 // Capture the old ConfigInfo reference
626 std::shared_ptr<ConfigInfo> oldConfigInfo = configInfo;
627
628 // Populate the new ConfigInfo object based on the histogramConfig pointer
629 configInfo = (histogramConfig) ? std::make_shared<ConfigInfo>(*histogramConfig) : nullptr;
630
631 if (!oldConfigInfo && !configInfo) {
632 return;
633 } else if (!oldConfigInfo && configInfo) { // Case #1: registerHistogram
634 addConfigToInactiveList(configInfo);
635 } else if (oldConfigInfo && configInfo) { // Case #2: reconfigHistogram
636 if (oldConfigInfo->mStatus == ConfigInfo::Status_t::HAS_CHANNEL_ASSIGNED) {
637 configInfo->mStatus = ConfigInfo::Status_t::HAS_CHANNEL_ASSIGNED;
638 configInfo->mChannelId = oldConfigInfo->mChannelId;
639 mChannels[configInfo->mChannelId].mStatus = ChannelStatus_t::CONFIG_PENDING;
640 mChannels[configInfo->mChannelId].mConfigInfo = configInfo;
641 } else if (oldConfigInfo->mStatus == ConfigInfo::Status_t::IN_INACTIVE_LIST) {
642 configInfo->mStatus = ConfigInfo::Status_t::IN_INACTIVE_LIST;
643 configInfo->mInactiveListIt = oldConfigInfo->mInactiveListIt;
644 *(configInfo->mInactiveListIt) = configInfo;
645 } else {
646 addConfigToInactiveList(configInfo);
647 }
648 } else if (oldConfigInfo && !configInfo) { // Case #3: unregisterHistogram
649 if (oldConfigInfo->mStatus == ConfigInfo::Status_t::HAS_CHANNEL_ASSIGNED)
650 cleanupChannelInfo(oldConfigInfo->mChannelId);
651 else if (oldConfigInfo->mStatus == ConfigInfo::Status_t::IN_INACTIVE_LIST)
652 mInactiveConfigItList.erase(oldConfigInfo->mInactiveListIt);
653
654 oldConfigInfo->mStatus = ConfigInfo::Status_t::INITIALIZED;
655 }
656
657 // Cleanup the blobIdData
658 if (oldConfigInfo) {
659 SCOPED_HIST_LOCK(mBlobIdDataMutex);
660 for (const auto& blobInfo : oldConfigInfo->mBlobsList)
661 mBlobIdDataMap.erase(blobInfo.mBlob->getId());
662 }
663 }
664
searchTokenInfo(const ndk::SpAIBinder & token,TokenInfo * & tokenInfo)665 HistogramDevice::HistogramErrorCode HistogramDevice::searchTokenInfo(const ndk::SpAIBinder& token,
666 TokenInfo*& tokenInfo) {
667 auto it = mTokenInfoMap.find(token.get());
668
669 if (it == mTokenInfoMap.end()) {
670 HIST_LOG(E, "BAD_TOKEN, token(%p) is not registered", token.get());
671 tokenInfo = nullptr;
672 return HistogramErrorCode::BAD_TOKEN;
673 }
674
675 tokenInfo = &it->second;
676 return HistogramErrorCode::NONE;
677 }
678
swapInConfigInfo(std::shared_ptr<ConfigInfo> & configInfo)679 std::list<std::weak_ptr<HistogramDevice::ConfigInfo>>::iterator HistogramDevice::swapInConfigInfo(
680 std::shared_ptr<ConfigInfo>& configInfo) {
681 // Acquire a free histogram channel, pdate used and free channels
682 const uint8_t channelId = mFreeChannels.front();
683 mFreeChannels.pop_front();
684 mUsedChannels.insert(channelId);
685
686 // update the ChannelInfo
687 ChannelInfo& channel = mChannels[channelId];
688 channel.mStatus = ChannelStatus_t::CONFIG_PENDING;
689 channel.mConfigInfo = configInfo;
690
691 // update the configInfo and the inactive list
692 configInfo->mStatus = ConfigInfo::Status_t::HAS_CHANNEL_ASSIGNED;
693 configInfo->mChannelId = channelId;
694 auto it = mInactiveConfigItList.erase(configInfo->mInactiveListIt);
695 configInfo->mInactiveListIt = mInactiveConfigItList.end();
696
697 return it;
698 }
699
swapOutConfigInfo(uint8_t channelId)700 void HistogramDevice::swapOutConfigInfo(uint8_t channelId) {
701 // Update used and free channels
702 mFreeChannels.push_back(channelId);
703 mUsedChannels.erase(channelId);
704
705 // update the ChannelInfo
706 ChannelInfo& channel = mChannels[channelId];
707 std::shared_ptr<ConfigInfo> configInfo = channel.mConfigInfo.lock();
708 channel.mStatus = ChannelStatus_t::DISABLE_PENDING;
709 channel.mConfigInfo.reset();
710
711 // update the configInfo and the inactive list
712 if (configInfo) {
713 uint32_t blobId = getActiveBlobId(configInfo->mBlobsList);
714 HIST_BLOB_CH_LOG(I, blobId, channelId, "configInfo(%p) is swapped out", configInfo.get());
715 addConfigToInactiveList(configInfo);
716 } else
717 HIST_CH_LOG(E, channelId, "expired configInfo, review code!");
718 }
719
addConfigToInactiveList(const std::shared_ptr<ConfigInfo> & configInfo,bool addToFront)720 void HistogramDevice::addConfigToInactiveList(const std::shared_ptr<ConfigInfo>& configInfo,
721 bool addToFront) {
722 configInfo->mChannelId = -1;
723 configInfo->mStatus = ConfigInfo::Status_t::IN_INACTIVE_LIST;
724 if (addToFront) {
725 configInfo->mInactiveListIt =
726 mInactiveConfigItList.emplace(mInactiveConfigItList.begin(), configInfo);
727 } else {
728 configInfo->mInactiveListIt =
729 mInactiveConfigItList.emplace(mInactiveConfigItList.end(), configInfo);
730 }
731 }
732
scheduler()733 bool HistogramDevice::scheduler() {
734 ATRACE_CALL();
735
736 bool needRefresh = false;
737
738 for (auto it = mInactiveConfigItList.begin(); it != mInactiveConfigItList.end();) {
739 if (mFreeChannels.empty()) break;
740
741 auto configInfo = it->lock();
742 if (!configInfo) {
743 HIST_LOG(W, "find expired configInfo ptr in mInactiveConfigItList, review code!");
744 it = mInactiveConfigItList.erase(it);
745 continue;
746 }
747
748 // Requires an onRefresh call to apply the config change of the channel
749 needRefresh = true;
750
751 // Swap in the config
752 it = swapInConfigInfo(configInfo);
753 }
754
755 return needRefresh;
756 }
757
searchOrCreateBlobIdData(uint32_t blobId,bool create,std::shared_ptr<BlobIdData> & blobIdData)758 void HistogramDevice::searchOrCreateBlobIdData(uint32_t blobId, bool create,
759 std::shared_ptr<BlobIdData>& blobIdData) {
760 ATRACE_CALL();
761 blobIdData = nullptr;
762 SCOPED_HIST_LOCK(mBlobIdDataMutex);
763
764 auto it = mBlobIdDataMap.find(blobId);
765 if (it != mBlobIdDataMap.end()) {
766 blobIdData = it->second;
767 } else if (create) {
768 std::shared_ptr<BlobIdData> blobIdDataTmp = std::make_shared<BlobIdData>();
769 mBlobIdDataMap.emplace(blobId, blobIdDataTmp);
770 blobIdData = blobIdDataTmp;
771 }
772 }
773
getChanIdBlobId(const ndk::SpAIBinder & token,HistogramErrorCode * histogramErrorCode,int & channelId,uint32_t & blobId)774 void HistogramDevice::getChanIdBlobId(const ndk::SpAIBinder& token,
775 HistogramErrorCode* histogramErrorCode, int& channelId,
776 uint32_t& blobId) {
777 ATRACE_CALL();
778 TokenInfo* tokenInfo = nullptr;
779 channelId = -1;
780 blobId = 0;
781
782 SCOPED_HIST_LOCK(mHistogramMutex);
783 if ((*histogramErrorCode = searchTokenInfo(token, tokenInfo)) != HistogramErrorCode::NONE) {
784 HIST_LOG(E, "searchTokenInfo failed, ret(%s)",
785 aidl::com::google::hardware::pixel::display::toString(*histogramErrorCode)
786 .c_str());
787 return;
788 }
789
790 std::shared_ptr<ConfigInfo>& configInfo = tokenInfo->mConfigInfo;
791 if (configInfo->mStatus == ConfigInfo::Status_t::HAS_CHANNEL_ASSIGNED)
792 channelId = configInfo->mChannelId;
793 else
794 channelId = -1;
795 #if defined(EXYNOS_CONTEXT_HISTOGRAM_EVENT_REQUEST)
796 blobId = getActiveBlobId(configInfo->mBlobsList);
797
798 if (!blobId) {
799 HIST_BLOB_CH_LOG(E, blobId, channelId, "CONFIG_HIST_ERROR, blob is not created yet");
800 *histogramErrorCode = HistogramErrorCode::CONFIG_HIST_ERROR;
801 return;
802 }
803 #else
804 // For the old kernel without blob id query supports, fake the blobId with channelId.
805 // In this hack way can prevent some duplicate codes just for channel id as well.
806 // In the future, all kernel will support blob id query. And can remove the hack.
807 blobId = channelId;
808 if (channelId < 0) {
809 HIST_BLOB_CH_LOG(E, blobId, channelId, "CONFIG_HIST_ERROR, no channel executes config");
810 *histogramErrorCode = HistogramErrorCode::CONFIG_HIST_ERROR;
811 return;
812 }
813 #endif
814 }
815
getHistogramData(const ndk::SpAIBinder & token,std::vector<char16_t> * histogramBuffer,HistogramErrorCode * histogramErrorCode)816 void HistogramDevice::getHistogramData(const ndk::SpAIBinder& token,
817 std::vector<char16_t>* histogramBuffer,
818 HistogramErrorCode* histogramErrorCode) {
819 ATRACE_CALL();
820
821 // default histogramErrorCode: no error
822 *histogramErrorCode = HistogramErrorCode::NONE;
823
824 // Get the current channelId and active blobId
825 int channelId;
826 uint32_t blobId;
827 getChanIdBlobId(token, histogramErrorCode, channelId, blobId);
828 if (*histogramErrorCode != HistogramErrorCode::NONE) return;
829
830 std::cv_status cv_status;
831
832 {
833 // Get the moduleDisplayInterface pointer
834 ExynosDisplayDrmInterface* moduleDisplayInterface =
835 static_cast<ExynosDisplayDrmInterface*>(mDisplay->mDisplayInterface.get());
836 if (!moduleDisplayInterface) {
837 *histogramErrorCode = HistogramErrorCode::ENABLE_HIST_ERROR;
838 HIST_BLOB_CH_LOG(E, blobId, channelId,
839 "ENABLE_HIST_ERROR, moduleDisplayInterface is NULL");
840 return;
841 }
842
843 // Use shared_ptr to keep the blobIdData which will be used by receiveBlobIdData and
844 // receiveBlobIdData.
845 std::shared_ptr<BlobIdData> blobIdData;
846 searchOrCreateBlobIdData(blobId, true, blobIdData);
847
848 std::unique_lock<std::mutex> lock(blobIdData->mDataCollectingMutex);
849 ::android::base::ScopedLockAssertion lock_assertion(blobIdData->mDataCollectingMutex);
850 ATRACE_NAME(String8::format("mDataCollectingMutex(blob#%u)", blobId));
851
852 // Request the drmEvent of the blobId (with mDataCollectingMutex held)
853 requestBlobIdData(moduleDisplayInterface, histogramErrorCode, channelId, blobId,
854 blobIdData);
855 if (*histogramErrorCode != HistogramErrorCode::NONE) return;
856
857 // Receive the drmEvent of the blobId (with mDataCollectingMutex held)
858 cv_status = receiveBlobIdData(moduleDisplayInterface, histogramBuffer, histogramErrorCode,
859 channelId, blobId, blobIdData, lock);
860 }
861
862 // Check the query result and clear the buffer if needed (no lock is held now)
863 checkQueryResult(histogramBuffer, histogramErrorCode, channelId, blobId, cv_status);
864 }
865
requestBlobIdData(ExynosDisplayDrmInterface * const moduleDisplayInterface,HistogramErrorCode * histogramErrorCode,const int channelId,const uint32_t blobId,const std::shared_ptr<BlobIdData> & blobIdData)866 void HistogramDevice::requestBlobIdData(ExynosDisplayDrmInterface* const moduleDisplayInterface,
867 HistogramErrorCode* histogramErrorCode, const int channelId,
868 const uint32_t blobId,
869 const std::shared_ptr<BlobIdData>& blobIdData) {
870 ATRACE_CALL();
871 int ret;
872
873 #if defined(EXYNOS_CONTEXT_HISTOGRAM_EVENT_REQUEST)
874 /* Send the ioctl request (histogram_event_request_ioctl) which increases the ref_cnt of the
875 * blobId request. The drm event is sent back with data when available. Must call
876 * sendContextHistogramIoctl(CANCEL) to decrease the ref_cnt after the request. */
877 if ((ret = moduleDisplayInterface->sendContextHistogramIoctl(ContextHistogramIoctl_t::REQUEST,
878 blobId)) != NO_ERROR) {
879 *histogramErrorCode = HistogramErrorCode::ENABLE_HIST_ERROR;
880 HIST_BLOB_CH_LOG(E, blobId, channelId,
881 "ENABLE_HIST_ERROR, sendContextHistogramIoctl(REQUEST) failed, ret(%d)",
882 ret);
883 return;
884 }
885 #else
886 /* Send the ioctl request (histogram_channel_request_ioctl) which increases the ref_cnt of the
887 * blobId request. The drm event is sent back with data when available. Must call
888 * sendHistogramChannelIoctl(CANCEL) to decrease the ref_cnt after the request. */
889 if ((ret = moduleDisplayInterface->sendHistogramChannelIoctl(HistogramChannelIoctl_t::REQUEST,
890 blobId)) != NO_ERROR) {
891 *histogramErrorCode = HistogramErrorCode::ENABLE_HIST_ERROR;
892 HIST_BLOB_CH_LOG(E, blobId, channelId,
893 "ENABLE_HIST_ERROR, sendHistogramChannelIoctl(REQUEST) failed, ret(%d)",
894 ret);
895 return;
896 }
897 #endif
898 blobIdData->mCollectStatus = CollectStatus_t::COLLECTING;
899 }
900
receiveBlobIdData(ExynosDisplayDrmInterface * const moduleDisplayInterface,std::vector<char16_t> * histogramBuffer,HistogramErrorCode * histogramErrorCode,const int channelId,const uint32_t blobId,const std::shared_ptr<BlobIdData> & blobIdData,std::unique_lock<std::mutex> & lock)901 std::cv_status HistogramDevice::receiveBlobIdData(
902 ExynosDisplayDrmInterface* const moduleDisplayInterface,
903 std::vector<char16_t>* histogramBuffer, HistogramErrorCode* histogramErrorCode,
904 const int channelId, const uint32_t blobId, const std::shared_ptr<BlobIdData>& blobIdData,
905 std::unique_lock<std::mutex>& lock) {
906 ATRACE_CALL();
907
908 // Wait until the condition variable is notified or timeout.
909 std::cv_status cv_status = std::cv_status::no_timeout;
910 if (blobIdData->mCollectStatus != CollectStatus_t::COLLECTED) {
911 ATRACE_NAME(String8::format("waitDrmEvent(noMutex,blob#%u)", blobId).c_str());
912 cv_status = blobIdData->mDataCollecting_cv.wait_for(lock, std::chrono::milliseconds(50));
913 }
914
915 // Wait for the drm event is finished, decrease ref_cnt.
916 int ret;
917 #if defined(EXYNOS_CONTEXT_HISTOGRAM_EVENT_REQUEST)
918 if ((ret = moduleDisplayInterface->sendContextHistogramIoctl(ContextHistogramIoctl_t::CANCEL,
919 blobId)) != NO_ERROR) {
920 HIST_BLOB_CH_LOG(W, blobId, channelId, "sendContextHistogramIoctl(CANCEL) failed, ret(%d)",
921 ret);
922 }
923 #else
924 if ((ret = moduleDisplayInterface->sendHistogramChannelIoctl(HistogramChannelIoctl_t::CANCEL,
925 blobId)) != NO_ERROR) {
926 HIST_BLOB_CH_LOG(W, blobId, channelId, "sendHistogramChannelIoctl(CANCEL) failed, ret(%d)",
927 ret);
928 }
929 #endif
930
931 /*
932 * Case #1: timeout occurs, status is not COLLECTED
933 * Case #2: no timeout, status is not COLLECTED
934 * Case #3: timeout occurs, status is COLLECTED
935 * Case #4: no timeout, status is COLLECTED
936 */
937 if (blobIdData->mCollectStatus == CollectStatus_t::COLLECTED) {
938 cv_status = std::cv_status::no_timeout; // ignore the timeout in Case #3
939 // Copy the histogram data from histogram info to histogramBuffer
940 histogramBuffer->assign(blobIdData->mData, blobIdData->mData + HISTOGRAM_BIN_COUNT);
941 } else {
942 // Case #1 and Case #2 will be checked by checkQueryResult
943 *histogramErrorCode = HistogramErrorCode::BAD_HIST_DATA;
944 blobIdData->mCollectStatus = CollectStatus_t::NOT_STARTED;
945 }
946
947 return cv_status;
948 }
949
checkQueryResult(std::vector<char16_t> * histogramBuffer,HistogramErrorCode * histogramErrorCode,const int channelId,const uint32_t blobId,const std::cv_status cv_status) const950 void HistogramDevice::checkQueryResult(std::vector<char16_t>* histogramBuffer,
951 HistogramErrorCode* histogramErrorCode, const int channelId,
952 const uint32_t blobId,
953 const std::cv_status cv_status) const {
954 ATRACE_CALL();
955
956 /*
957 * It may take for a while in isSecureContentPresenting() and isPowerModeOff().
958 * We should not hold any lock from the caller.
959 */
960 if (mDisplay->isSecureContentPresenting()) {
961 HIST_BLOB_CH_LOG(V, blobId, channelId,
962 "DRM_PLAYING, data is not available when secure content is presenting");
963 *histogramErrorCode = HistogramErrorCode::DRM_PLAYING;
964 } else if (*histogramErrorCode != HistogramErrorCode::NONE) {
965 if (cv_status == std::cv_status::timeout) {
966 if (mDisplay->isPowerModeOff()) {
967 HIST_BLOB_CH_LOG(W, blobId, channelId, "DISPLAY_POWEROFF, data is not available");
968 *histogramErrorCode = HistogramErrorCode::DISPLAY_POWEROFF;
969 } else {
970 HIST_BLOB_CH_LOG(E, blobId, channelId, "BAD_HIST_DATA, no event is handled");
971 *histogramErrorCode = HistogramErrorCode::BAD_HIST_DATA;
972 }
973 } else {
974 HIST_BLOB_CH_LOG(I, blobId, channelId, "RRS detected, cv is notified without data");
975 }
976 }
977
978 if (*histogramErrorCode != HistogramErrorCode::NONE) {
979 // Clear the histogramBuffer when error occurs
980 histogramBuffer->assign(HISTOGRAM_BIN_COUNT, 0);
981 }
982
983 ATRACE_NAME(aidl::com::google::hardware::pixel::display::toString(*histogramErrorCode).c_str());
984 }
985
986 // TODO: b/295990513 - Remove the if defined after kernel prebuilts are merged.
987 #if defined(EXYNOS_HISTOGRAM_CHANNEL_REQUEST)
parseDrmEvent(const void * const event,uint32_t & channelId,char16_t * & buffer) const988 int HistogramDevice::parseDrmEvent(const void* const event, uint32_t& channelId,
989 char16_t*& buffer) const {
990 ATRACE_NAME(String8::format("parseHistogramDrmEvent(%p)", event).c_str());
991 if (!event) {
992 HIST_LOG(E, "event is NULL");
993 return BAD_VALUE;
994 }
995
996 const struct exynos_drm_histogram_channel_event* const histogram_channel_event =
997 (struct exynos_drm_histogram_channel_event*)event;
998 channelId = histogram_channel_event->hist_id;
999 buffer = (char16_t*)&histogram_channel_event->bins;
1000 return NO_ERROR;
1001 }
1002 #else
parseDrmEvent(const void * const event,uint32_t & channelId,char16_t * & buffer) const1003 int HistogramDevice::parseDrmEvent(const void* const event, uint32_t& channelId,
1004 char16_t*& buffer) const {
1005 HIST_LOG(E,
1006 "not supported by kernel, struct exynos_drm_histogram_channel_event is not defined");
1007 channelId = 0;
1008 buffer = nullptr;
1009 return INVALID_OPERATION;
1010 }
1011 #endif
1012
1013 #if defined(EXYNOS_CONTEXT_HISTOGRAM_EVENT_REQUEST)
parseContextDrmEvent(const void * const event,uint32_t & blobId,char16_t * & buffer) const1014 int HistogramDevice::parseContextDrmEvent(const void* const event, uint32_t& blobId,
1015 char16_t*& buffer) const {
1016 ATRACE_NAME(String8::format("parseHistogramDrmEvent(%p)", event).c_str());
1017 if (!event) {
1018 HIST_LOG(E, "event is NULL");
1019 return BAD_VALUE;
1020 }
1021
1022 const struct exynos_drm_context_histogram_event* const context_histogram_event =
1023 (struct exynos_drm_context_histogram_event*)event;
1024 blobId = context_histogram_event->user_handle;
1025 buffer = (char16_t*)&context_histogram_event->bins;
1026 return NO_ERROR;
1027 }
1028 #else
parseContextDrmEvent(const void * const event,uint32_t & blobId,char16_t * & buffer) const1029 int HistogramDevice::parseContextDrmEvent(const void* const event, uint32_t& blobId,
1030 char16_t*& buffer) const {
1031 HIST_LOG(E,
1032 "not supported by kernel, struct exynos_drm_context_histogram_event is not defined");
1033 blobId = 0;
1034 buffer = nullptr;
1035 return INVALID_OPERATION;
1036 }
1037 #endif
1038
cleanupChannelInfo(const uint8_t channelId)1039 std::set<const uint8_t>::iterator HistogramDevice::cleanupChannelInfo(const uint8_t channelId) {
1040 mChannels[channelId].mStatus = ChannelStatus_t::DISABLE_PENDING;
1041 mChannels[channelId].mConfigInfo.reset();
1042 mFreeChannels.push_back(channelId);
1043 return mUsedChannels.erase(mUsedChannels.find(channelId));
1044 }
1045
setChannelConfigBlob(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const uint8_t channelId,ExynosDisplayDrmInterface * const moduleDisplayInterface,const int displayActiveH,const int displayActiveV,const std::shared_ptr<ConfigInfo> & configInfo)1046 void HistogramDevice::setChannelConfigBlob(ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq,
1047 const uint8_t channelId,
1048 ExynosDisplayDrmInterface* const moduleDisplayInterface,
1049 const int displayActiveH, const int displayActiveV,
1050 const std::shared_ptr<ConfigInfo>& configInfo) {
1051 ATRACE_NAME(String8::format("%s(chan#%u)", __func__, channelId));
1052 ChannelInfo& channel = mChannels[channelId];
1053 int ret;
1054 bool isRRS = false;
1055 uint32_t blobId = getMatchBlobId(configInfo->mBlobsList, displayActiveH, displayActiveV, isRRS);
1056
1057 // Early return for config blob already committed and no RRS occurs.
1058 if (channel.mStatus == ChannelStatus_t::CONFIG_COMMITTED && blobId && !isRRS) return;
1059
1060 // Create the histogram config blob when no matched blob found.
1061 if (!blobId) {
1062 std::shared_ptr<PropertyBlob> drmConfigBlob;
1063 ret = createDrmConfigBlob(configInfo->mRequestedConfig, displayActiveH, displayActiveV,
1064 drmConfigBlob);
1065 if (ret || !drmConfigBlob) {
1066 if (ret == NO_INIT) {
1067 HIST_CH_LOG(D, channelId, "skip channel config");
1068 channel.mStatus = ChannelStatus_t::CONFIG_PENDING;
1069 } else {
1070 HIST_CH_LOG(E, channelId, "createDrmConfigBlob failed, ret(%d)", ret);
1071 channel.mStatus = ChannelStatus_t::CONFIG_ERROR;
1072 }
1073 return;
1074 }
1075
1076 // Attach the histogram drmConfigBlob to the configInfo
1077 if (!configInfo->mBlobsList.empty()) isRRS = true;
1078 configInfo->mBlobsList.emplace_front(displayActiveH, displayActiveV, drmConfigBlob);
1079 blobId = drmConfigBlob->getId();
1080 }
1081
1082 if (channel.mStatus == ChannelStatus_t::CONFIG_COMMITTED && isRRS) {
1083 HIST_BLOB_CH_LOG(I, blobId, channelId, "RRS (%dx%d) detected", displayActiveH,
1084 displayActiveV);
1085 }
1086
1087 // Add histogram config blob to atomic commit
1088 if ((ret = moduleDisplayInterface->setHistogramChannelConfigBlob(drmReq, channelId, blobId))) {
1089 HIST_BLOB_CH_LOG(E, blobId, channelId, "setHistogramChannelConfigBlob failed, ret(%d)",
1090 ret);
1091 channel.mStatus = ChannelStatus_t::CONFIG_ERROR;
1092 } else {
1093 channel.mStatus = ChannelStatus_t::CONFIG_BLOB_ADDED;
1094 }
1095 }
1096
clearChannelConfigBlob(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const uint8_t channelId,ExynosDisplayDrmInterface * const moduleDisplayInterface)1097 void HistogramDevice::clearChannelConfigBlob(
1098 ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq, const uint8_t channelId,
1099 ExynosDisplayDrmInterface* const moduleDisplayInterface) {
1100 ATRACE_NAME(String8::format("%s(chan#%u)", __func__, channelId));
1101 ChannelInfo& channel = mChannels[channelId];
1102 int ret;
1103
1104 if ((ret = moduleDisplayInterface->clearHistogramChannelConfigBlob(drmReq, channelId))) {
1105 HIST_CH_LOG(E, channelId, "clearHistogramChannelConfigBlob failed, ret(%d)", ret);
1106 channel.mStatus = ChannelStatus_t::DISABLE_ERROR;
1107 } else {
1108 channel.mStatus = ChannelStatus_t::DISABLE_BLOB_ADDED;
1109 }
1110 }
1111
getMatchBlobId(std::list<const BlobInfo> & blobsList,const int displayActiveH,const int displayActiveV,bool & isPositionChanged) const1112 uint32_t HistogramDevice::getMatchBlobId(std::list<const BlobInfo>& blobsList,
1113 const int displayActiveH, const int displayActiveV,
1114 bool& isPositionChanged) const {
1115 auto resultIt = blobsList.end();
1116
1117 for (auto it = blobsList.begin(); it != blobsList.end(); ++it) {
1118 if (it->mDisplayActiveH == displayActiveH && it->mDisplayActiveV == displayActiveV) {
1119 resultIt = it;
1120 break;
1121 }
1122 }
1123
1124 if (resultIt == blobsList.end()) return 0;
1125
1126 // Move the matched config blob to the front
1127 if (resultIt != blobsList.begin()) {
1128 isPositionChanged = true;
1129 blobsList.splice(blobsList.begin(), blobsList, resultIt, std::next(resultIt));
1130 }
1131
1132 return blobsList.begin()->mBlob->getId();
1133 }
1134
getActiveBlobId(const std::list<const BlobInfo> & blobsList) const1135 uint32_t HistogramDevice::getActiveBlobId(const std::list<const BlobInfo>& blobsList) const {
1136 return blobsList.empty() ? 0 : blobsList.begin()->mBlob->getId();
1137 }
1138
1139 // TODO: b/295990513 - Remove the if defined after kernel prebuilts are merged.
1140 #if defined(EXYNOS_HISTOGRAM_CHANNEL_REQUEST)
createDrmConfig(const HistogramConfig & histogramConfig,const int displayActiveH,const int displayActiveV,std::shared_ptr<void> & drmConfig,size_t & drmConfigLength) const1141 int HistogramDevice::createDrmConfig(const HistogramConfig& histogramConfig,
1142 const int displayActiveH, const int displayActiveV,
1143 std::shared_ptr<void>& drmConfig,
1144 size_t& drmConfigLength) const {
1145 int ret = NO_ERROR;
1146
1147 if (UNLIKELY(!displayActiveH || !displayActiveV)) {
1148 HIST_LOG(I, "active mode (%dx%d) is not initialized, skip creation", displayActiveH,
1149 displayActiveV);
1150 return NO_INIT;
1151 }
1152
1153 HistogramRoiRect drmRoi, drmBlockingRoi;
1154 if (UNLIKELY(ret = convertRoi(histogramConfig.roi, drmRoi, displayActiveH, displayActiveV,
1155 ""))) {
1156 HIST_LOG(E, "failed to convert roi, ret(%d)", ret);
1157 return ret;
1158 }
1159 if (UNLIKELY(ret = convertRoi(histogramConfig.blockingRoi.value_or(DISABLED_ROI),
1160 drmBlockingRoi, displayActiveH, displayActiveV, "blocking "))) {
1161 HIST_LOG(E, "failed to convert blocking roi, ret(%d)", ret);
1162 return ret;
1163 }
1164
1165 drmConfig = std::make_shared<struct histogram_channel_config>();
1166 struct histogram_channel_config* config = (struct histogram_channel_config*)drmConfig.get();
1167 config->roi.start_x = drmRoi.left;
1168 config->roi.start_y = drmRoi.top;
1169 config->roi.hsize = drmRoi.right - drmRoi.left;
1170 config->roi.vsize = drmRoi.bottom - drmRoi.top;
1171 if (drmBlockingRoi != DISABLED_ROI) {
1172 config->flags |= HISTOGRAM_FLAGS_BLOCKED_ROI;
1173 config->blocked_roi.start_x = drmBlockingRoi.left;
1174 config->blocked_roi.start_y = drmBlockingRoi.top;
1175 config->blocked_roi.hsize = drmBlockingRoi.right - drmBlockingRoi.left;
1176 config->blocked_roi.vsize = drmBlockingRoi.bottom - drmBlockingRoi.top;
1177 } else {
1178 config->flags &= ~HISTOGRAM_FLAGS_BLOCKED_ROI;
1179 }
1180 config->weights.weight_r = histogramConfig.weights.weightR;
1181 config->weights.weight_g = histogramConfig.weights.weightG;
1182 config->weights.weight_b = histogramConfig.weights.weightB;
1183 config->pos =
1184 (histogramConfig.samplePos == HistogramSamplePos::POST_POSTPROC) ? POST_DQE : PRE_DQE;
1185 config->threshold = calculateThreshold(drmRoi, displayActiveH, displayActiveV);
1186
1187 drmConfigLength = sizeof(struct histogram_channel_config);
1188
1189 return NO_ERROR;
1190 }
1191 #else
createDrmConfig(const HistogramConfig & histogramConfig,const int displayActiveH,const int displayActiveV,std::shared_ptr<void> & drmConfig,size_t & drmConfigLength) const1192 int HistogramDevice::createDrmConfig(const HistogramConfig& histogramConfig,
1193 const int displayActiveH, const int displayActiveV,
1194 std::shared_ptr<void>& drmConfig,
1195 size_t& drmConfigLength) const {
1196 HIST_LOG(E, "not supported by kernel, struct histogram_channel_config is not defined");
1197 drmConfig = nullptr;
1198 drmConfigLength = 0;
1199 return INVALID_OPERATION;
1200 }
1201 #endif
1202
createDrmConfigBlob(const HistogramConfig & histogramConfig,const int displayActiveH,const int displayActiveV,std::shared_ptr<PropertyBlob> & drmConfigBlob) const1203 int HistogramDevice::createDrmConfigBlob(const HistogramConfig& histogramConfig,
1204 const int displayActiveH, const int displayActiveV,
1205 std::shared_ptr<PropertyBlob>& drmConfigBlob) const {
1206 int ret = NO_ERROR;
1207 std::shared_ptr<void> drmConfig;
1208 size_t drmConfigLength = 0;
1209
1210 if ((ret = createDrmConfig(histogramConfig, displayActiveH, displayActiveV, drmConfig,
1211 drmConfigLength)))
1212 return ret;
1213
1214 std::shared_ptr<PropertyBlob> drmConfigBlobTmp =
1215 std::make_shared<PropertyBlob>(mDrmDevice, drmConfig.get(), drmConfigLength);
1216 if ((ret = drmConfigBlobTmp->getError())) {
1217 HIST_LOG(E, "failed to create property blob, ret(%d)", ret);
1218 return ret;
1219 }
1220
1221 // If success, drmConfigBlobTmp must contain a non-zero blobId
1222 drmConfigBlob = drmConfigBlobTmp;
1223
1224 return NO_ERROR;
1225 }
1226
resetConfigInfoStatus(std::shared_ptr<ConfigInfo> & configInfo)1227 void HistogramDevice::resetConfigInfoStatus(std::shared_ptr<ConfigInfo>& configInfo) {
1228 if (configInfo->mStatus == ConfigInfo::Status_t::HAS_CHANNEL_ASSIGNED)
1229 cleanupChannelInfo(configInfo->mChannelId);
1230 else if (configInfo->mStatus == ConfigInfo::Status_t::IN_INACTIVE_LIST) {
1231 mInactiveConfigItList.erase(configInfo->mInactiveListIt);
1232 configInfo->mInactiveListIt = mInactiveConfigItList.end();
1233 }
1234
1235 configInfo->mStatus = ConfigInfo::Status_t::INITIALIZED;
1236 }
1237
snapDisplayActiveSize() const1238 std::pair<int, int> HistogramDevice::snapDisplayActiveSize() const {
1239 ExynosDisplayDrmInterface* moduleDisplayInterface =
1240 static_cast<ExynosDisplayDrmInterface*>(mDisplay->mDisplayInterface.get());
1241 if (!moduleDisplayInterface) {
1242 HIST_LOG(E, "failed to get active size, moduleDisplayInterface is NULL");
1243 return std::make_pair(0, 0);
1244 }
1245
1246 return std::make_pair(moduleDisplayInterface->getActiveModeHDisplay(),
1247 moduleDisplayInterface->getActiveModeVDisplay());
1248 }
1249
convertRoi(const HistogramRoiRect & requestedRoi,HistogramRoiRect & convertedRoi,const int displayActiveH,const int displayActiveV,const char * roiType) const1250 int HistogramDevice::convertRoi(const HistogramRoiRect& requestedRoi,
1251 HistogramRoiRect& convertedRoi, const int displayActiveH,
1252 const int displayActiveV, const char* roiType) const {
1253 int32_t panelH, panelV;
1254
1255 {
1256 std::shared_lock lock(mHistogramCapabilityMutex);
1257 panelH = mHistogramCapability.fullResolutionWidth;
1258 panelV = mHistogramCapability.fullResolutionHeight;
1259 }
1260
1261 HIST_LOG(V, "active: (%dx%d), panel: (%dx%d)", displayActiveH, displayActiveV, panelH, panelV);
1262
1263 if (panelH < displayActiveH || displayActiveH < 0 || panelV < displayActiveV ||
1264 displayActiveV < 0) {
1265 HIST_LOG(E, "failed to convert %sroi, active: (%dx%d), panel: (%dx%d)", roiType,
1266 displayActiveH, displayActiveV, panelH, panelV);
1267 return -EINVAL;
1268 }
1269
1270 // Linear transform from full resolution to active resolution
1271 convertedRoi.left = requestedRoi.left * displayActiveH / panelH;
1272 convertedRoi.top = requestedRoi.top * displayActiveV / panelV;
1273 convertedRoi.right = requestedRoi.right * displayActiveH / panelH;
1274 convertedRoi.bottom = requestedRoi.bottom * displayActiveV / panelV;
1275
1276 HIST_LOG(V, "working %sroi: %s", roiType, toString(convertedRoi).c_str());
1277
1278 return NO_ERROR;
1279 }
1280
dumpHistogramCapability(String8 & result) const1281 void HistogramDevice::dumpHistogramCapability(String8& result) const {
1282 std::shared_lock lock(mHistogramCapabilityMutex);
1283 // Append the histogram capability info to the dump string
1284 result.appendFormat("Histogram capability(%s):\n",
1285 (mDisplay) ? (mDisplay->mDisplayName.c_str()) : "NULL");
1286 result.appendFormat("\tsupportMultiChannel: %s, ",
1287 mHistogramCapability.supportMultiChannel ? "true" : "false");
1288 result.appendFormat("supportBlockingRoi: %s, ",
1289 mHistogramCapability.supportBlockingRoi ? "true" : "false");
1290 result.appendFormat("supportQueryOpr: %s, ",
1291 mHistogramCapability.supportQueryOpr ? "true" : "false");
1292 result.appendFormat("supportSamplePosList:");
1293 for (HistogramSamplePos samplePos : mHistogramCapability.supportSamplePosList) {
1294 result.appendFormat(" %s",
1295 aidl::com::google::hardware::pixel::display::toString(samplePos)
1296 .c_str());
1297 }
1298 result.appendFormat("\n");
1299 result.appendFormat("\tchannelCount: %d, ", mHistogramCapability.channelCount);
1300 result.appendFormat("fullscreen roi: (0,0)x(%dx%d)\n", mHistogramCapability.fullResolutionWidth,
1301 mHistogramCapability.fullResolutionHeight);
1302 }
1303
1304 // TODO: b/295990513 - Remove the if defined after kernel prebuilts are merged.
1305 #if defined(EXYNOS_HISTOGRAM_CHANNEL_REQUEST)
dumpChannel(TableBuilder & tb,const uint8_t channelId) const1306 void HistogramDevice::dumpChannel(TableBuilder& tb, const uint8_t channelId) const {
1307 const ChannelInfo& channel = mChannels[channelId];
1308 auto configInfo = channel.mConfigInfo.lock();
1309 uint32_t blobId = configInfo ? getActiveBlobId(configInfo->mBlobsList) : 0;
1310 drmModePropertyBlobPtr blob = nullptr;
1311
1312 // Get the histogram config blob
1313 if (blobId && mDrmDevice) {
1314 if ((blob = drmModeGetPropertyBlob(mDrmDevice->fd(), blobId)) == nullptr) {
1315 HIST_BLOB_CH_LOG(E, blobId, channelId,
1316 "drmModeGetPropertyBlob failed, blob is nullptr");
1317 }
1318 }
1319
1320 tb.add("ID", (int)channelId);
1321 tb.add("status", toString(channel.mStatus));
1322 tb.add("configInfo", configInfo.get());
1323
1324 if (!blob) {
1325 if (blobId)
1326 tb.add("blobId", String8::format("%u (Get failed)", blobId));
1327 else
1328 tb.add("blobId", "N/A");
1329 tb.add("workingRoi", "N/A");
1330 tb.add("workingBlockRoi", "N/A");
1331 tb.add("threshold", "N/A");
1332 tb.add("weightRGB", "N/A");
1333 tb.add("samplePos", "N/A");
1334 return;
1335 }
1336
1337 const struct histogram_channel_config* config =
1338 reinterpret_cast<struct histogram_channel_config*>(blob->data);
1339 HistogramRoiRect workingRoi = {config->roi.start_x, config->roi.start_y,
1340 config->roi.start_x + config->roi.hsize,
1341 config->roi.start_y + config->roi.vsize};
1342 HistogramRoiRect workingBlockRoi = {config->blocked_roi.start_x, config->blocked_roi.start_y,
1343 config->blocked_roi.start_x + config->blocked_roi.hsize,
1344 config->blocked_roi.start_y + config->blocked_roi.vsize};
1345 tb.add("blobId", blobId);
1346 tb.add("workingRoi", toString(workingRoi));
1347 tb.add("workingBlockRoi", toString(workingBlockRoi));
1348 tb.add("threshold", config->threshold);
1349 tb.add("weightRGB",
1350 String8::format("(%" PRIu16 ",%" PRIu16 ",%" PRIu16 ")", config->weights.weight_r,
1351 config->weights.weight_g, config->weights.weight_b));
1352 tb.add("samplePos", config->pos == POST_DQE ? "POST_DQE" : "PRE_DQE");
1353 drmModeFreePropertyBlob(blob);
1354 }
1355 #else
dumpChannel(TableBuilder & tb,const uint8_t channelId) const1356 void HistogramDevice::dumpChannel(TableBuilder& tb, const uint8_t channelId) const {}
1357 #endif
1358
validateHistogramRequest(const ndk::SpAIBinder & token,const HistogramConfig & histogramConfig,HistogramErrorCode * histogramErrorCode) const1359 ndk::ScopedAStatus HistogramDevice::validateHistogramRequest(
1360 const ndk::SpAIBinder& token, const HistogramConfig& histogramConfig,
1361 HistogramErrorCode* histogramErrorCode) const {
1362 // validate the argument (histogramErrorCode)
1363 if (!histogramErrorCode) {
1364 HIST_LOG(E, "binder error, histogramErrorCode is nullptr");
1365 return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
1366 }
1367
1368 // default histogramErrorCode: no error
1369 *histogramErrorCode = HistogramErrorCode::NONE;
1370
1371 // validate the argument (token)
1372 if (token.get() == nullptr) {
1373 HIST_LOG(E, "BAD_TOKEN, token is nullptr");
1374 *histogramErrorCode = HistogramErrorCode::BAD_TOKEN;
1375 return ndk::ScopedAStatus::ok();
1376 }
1377
1378 // validate the argument (histogramConfig)
1379 if ((*histogramErrorCode = validateHistogramConfig(histogramConfig)) !=
1380 HistogramErrorCode::NONE) {
1381 return ndk::ScopedAStatus::ok();
1382 }
1383
1384 return ndk::ScopedAStatus::ok();
1385 }
1386
validateHistogramConfig(const HistogramConfig & histogramConfig) const1387 HistogramDevice::HistogramErrorCode HistogramDevice::validateHistogramConfig(
1388 const HistogramConfig& histogramConfig) const {
1389 HistogramErrorCode ret;
1390
1391 std::shared_lock lock(mHistogramCapabilityMutex);
1392
1393 if ((ret = validateHistogramRoi(histogramConfig.roi, "")) != HistogramErrorCode::NONE ||
1394 (ret = validateHistogramWeights(histogramConfig.weights)) != HistogramErrorCode::NONE ||
1395 (ret = validateHistogramSamplePos(histogramConfig.samplePos)) != HistogramErrorCode::NONE ||
1396 (ret = validateHistogramBlockingRoi(histogramConfig.blockingRoi)) !=
1397 HistogramErrorCode::NONE) {
1398 return ret;
1399 }
1400
1401 return HistogramErrorCode::NONE;
1402 }
1403
validateHistogramRoi(const HistogramRoiRect & roi,const char * roiType) const1404 HistogramDevice::HistogramErrorCode HistogramDevice::validateHistogramRoi(
1405 const HistogramRoiRect& roi, const char* roiType) const {
1406 if (roi == DISABLED_ROI) return HistogramErrorCode::NONE;
1407
1408 if ((roi.left < 0) || (roi.top < 0) || (roi.right - roi.left <= 0) ||
1409 (roi.bottom - roi.top <= 0) || (roi.right > mHistogramCapability.fullResolutionWidth) ||
1410 (roi.bottom > mHistogramCapability.fullResolutionHeight)) {
1411 HIST_LOG(E, "BAD_ROI, %sroi: %s, full screen roi: (0,0)x(%dx%d)", roiType,
1412 toString(roi).c_str(), mHistogramCapability.fullResolutionWidth,
1413 mHistogramCapability.fullResolutionHeight);
1414 return HistogramErrorCode::BAD_ROI;
1415 }
1416
1417 return HistogramErrorCode::NONE;
1418 }
1419
validateHistogramWeights(const HistogramWeights & weights) const1420 HistogramDevice::HistogramErrorCode HistogramDevice::validateHistogramWeights(
1421 const HistogramWeights& weights) const {
1422 if ((weights.weightR + weights.weightG + weights.weightB) != WEIGHT_SUM) {
1423 HIST_LOG(E, "BAD_WEIGHT, weights%s", toString(weights).c_str());
1424 return HistogramErrorCode::BAD_WEIGHT;
1425 }
1426
1427 return HistogramErrorCode::NONE;
1428 }
1429
validateHistogramSamplePos(const HistogramSamplePos & samplePos) const1430 HistogramDevice::HistogramErrorCode HistogramDevice::validateHistogramSamplePos(
1431 const HistogramSamplePos& samplePos) const {
1432 for (HistogramSamplePos mSamplePos : mHistogramCapability.supportSamplePosList) {
1433 if (samplePos == mSamplePos) {
1434 return HistogramErrorCode::NONE;
1435 }
1436 }
1437
1438 HIST_LOG(E, "BAD_POSITION, samplePos is %s",
1439 aidl::com::google::hardware::pixel::display::toString(samplePos).c_str());
1440 return HistogramErrorCode::BAD_POSITION;
1441 }
1442
validateHistogramBlockingRoi(const std::optional<HistogramRoiRect> & blockingRoi) const1443 HistogramDevice::HistogramErrorCode HistogramDevice::validateHistogramBlockingRoi(
1444 const std::optional<HistogramRoiRect>& blockingRoi) const {
1445 // If the platform doesn't support blockingRoi, client should not enable blockingRoi
1446 if (mHistogramCapability.supportBlockingRoi == false) {
1447 if (blockingRoi.has_value() && blockingRoi.value() != DISABLED_ROI) {
1448 HIST_LOG(E, "BAD_ROI, platform doesn't support blockingRoi, requested: %s",
1449 toString(blockingRoi.value()).c_str());
1450 return HistogramErrorCode::BAD_ROI;
1451 }
1452 return HistogramErrorCode::NONE;
1453 }
1454
1455 // For the platform that supports blockingRoi, use the same validate rule as roi
1456 return validateHistogramRoi(blockingRoi.value_or(DISABLED_ROI), "blocking ");
1457 }
1458
calculateThreshold(const HistogramRoiRect & roi,const int displayActiveH,const int displayActiveV) const1459 int HistogramDevice::calculateThreshold(const HistogramRoiRect& roi, const int displayActiveH,
1460 const int displayActiveV) const {
1461 // If roi is disabled, the targeted region is entire screen.
1462 int32_t roiH = (roi != DISABLED_ROI) ? (roi.right - roi.left) : displayActiveH;
1463 int32_t roiV = (roi != DISABLED_ROI) ? (roi.bottom - roi.top) : displayActiveV;
1464 int threshold = (roiV * roiH) >> 16;
1465 // TODO: b/294491895 - Check if the threshold plus one really need it
1466 return threshold + 1;
1467 }
1468
toString(const ChannelStatus_t & status)1469 std::string HistogramDevice::toString(const ChannelStatus_t& status) {
1470 switch (status) {
1471 case ChannelStatus_t::RESERVED:
1472 return "RESERVED";
1473 case ChannelStatus_t::DISABLED:
1474 return "DISABLED";
1475 case ChannelStatus_t::CONFIG_PENDING:
1476 return "CONFIG_PENDING";
1477 case ChannelStatus_t::CONFIG_BLOB_ADDED:
1478 return "CONFIG_BLOB_ADDED";
1479 case ChannelStatus_t::CONFIG_COMMITTED:
1480 return "CONFIG_COMMITTED";
1481 case ChannelStatus_t::CONFIG_ERROR:
1482 return "CONFIG_ERROR";
1483 case ChannelStatus_t::DISABLE_PENDING:
1484 return "DISABLE_PENDING";
1485 case ChannelStatus_t::DISABLE_BLOB_ADDED:
1486 return "DISABLE_BLOB_ADDED";
1487 case ChannelStatus_t::DISABLE_ERROR:
1488 return "DISABLE_ERROR";
1489 }
1490
1491 return "UNDEFINED";
1492 }
1493
toString(const HistogramRoiRect & roi)1494 std::string HistogramDevice::toString(const HistogramRoiRect& roi) {
1495 if (roi == DISABLED_ROI) return "OFF";
1496
1497 std::ostringstream os;
1498 os << "(" << roi.left << "," << roi.top << ")";
1499 os << "x";
1500 os << "(" << roi.right << "," << roi.bottom << ")";
1501 return os.str();
1502 }
1503
toString(const HistogramWeights & weights)1504 std::string HistogramDevice::toString(const HistogramWeights& weights) {
1505 std::ostringstream os;
1506 os << "(";
1507 os << (int)weights.weightR << ",";
1508 os << (int)weights.weightG << ",";
1509 os << (int)weights.weightB;
1510 os << ")";
1511 return os.str();
1512 }
1513
toString(const HistogramConfig & config)1514 std::string HistogramDevice::toString(const HistogramConfig& config) {
1515 std::ostringstream os;
1516 os << "roi:" << toString(config.roi) << ", ";
1517 os << "blockRoi:" << toString(config.blockingRoi.value_or(DISABLED_ROI)) << ", ";
1518 os << "weightRGB:" << toString(config.weights) << ", ";
1519 os << "samplePos:" << aidl::com::google::hardware::pixel::display::toString(config.samplePos);
1520 return os.str();
1521 }
1522
dump(String8 & result,const char * prefix) const1523 void HistogramDevice::TokenInfo::dump(String8& result, const char* prefix) const {
1524 result.appendFormat("%sHistogram token %p:\n", prefix, mToken.get());
1525 result.appendFormat("%s\tpid: %d\n", prefix, mPid);
1526 if (!mConfigInfo) {
1527 result.append("%s\tconfigInfo: (nullptr)\n");
1528 }
1529 }
1530
dump(String8 & result,const char * prefix) const1531 void HistogramDevice::ConfigInfo::dump(String8& result, const char* prefix) const {
1532 result.appendFormat("%sconfigInfo: %p -> ", prefix, this);
1533 if (mStatus == Status_t::HAS_CHANNEL_ASSIGNED)
1534 result.appendFormat("channelId: %d\n", mChannelId);
1535 else if (mStatus == Status_t::IN_INACTIVE_LIST)
1536 result.appendFormat("inactive list: queued\n");
1537 else
1538 result.appendFormat("inactive list: N/A\n");
1539 result.appendFormat("%s\trequestedConfig: %s\n", prefix, toString(mRequestedConfig).c_str());
1540 result.appendFormat("%s\tblobsList: ", prefix);
1541 if (!mBlobsList.empty()) {
1542 result.append("*");
1543 for (auto it = mBlobsList.begin(); it != mBlobsList.end(); ++it) {
1544 result.appendFormat("blob#%u(%dx%d) ", it->mBlob->getId(), it->mDisplayActiveH,
1545 it->mDisplayActiveV);
1546 }
1547 } else {
1548 result.append("none");
1549 }
1550 result.append("\n");
1551 }
1552
PropertyBlob(DrmDevice * const drmDevice,const void * const blobData,const size_t blobLength)1553 HistogramDevice::PropertyBlob::PropertyBlob(DrmDevice* const drmDevice, const void* const blobData,
1554 const size_t blobLength)
1555 : mDrmDevice(drmDevice) {
1556 if (!mDrmDevice) {
1557 ALOGE("%s: mDrmDevice is nullptr", __func__);
1558 mError = BAD_VALUE;
1559 return;
1560 }
1561
1562 if ((mError = mDrmDevice->CreatePropertyBlob(blobData, blobLength, &mBlobId))) {
1563 mBlobId = 0;
1564 ALOGE("%s: failed to create histogram config blob, ret(%d)", __func__, mError);
1565 } else if (!mBlobId) {
1566 mError = BAD_VALUE;
1567 ALOGE("%s: create histogram config blob successful, but blobId is 0", __func__);
1568 }
1569 }
1570
~PropertyBlob()1571 HistogramDevice::PropertyBlob::~PropertyBlob() {
1572 if (mError) return;
1573
1574 int ret = mDrmDevice->DestroyPropertyBlob(mBlobId);
1575 if (ret)
1576 ALOGE("%s: failed to destroy histogram config blob %d, ret(%d)", __func__, mBlobId, ret);
1577 }
1578
getId() const1579 uint32_t HistogramDevice::PropertyBlob::getId() const {
1580 return mBlobId;
1581 }
1582
getError() const1583 int HistogramDevice::PropertyBlob::getError() const {
1584 return mError;
1585 }
1586