1 /*
2  * Copyright (C) 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 "pixel-display.h"
18 
19 #include <aidlcommonsupport/NativeHandle.h>
20 #include <android-base/logging.h>
21 #include <android/binder_manager.h>
22 #include <android/binder_process.h>
23 #include <sys/types.h>
24 #include <utils/Errors.h>
25 #include <cstdint>
26 
27 #include "BrightnessController.h"
28 #include "ExynosDisplay.h"
29 #include "ExynosPrimaryDisplay.h"
30 #include "HistogramController.h"
31 
32 extern int32_t load_png_image(const char *filepath, buffer_handle_t buffer);
33 
34 using ::aidl::com::google::hardware::pixel::display::Display;
35 
PixelDisplayInit(ExynosDisplay * exynos_display,const std::string_view instance_str)36 void PixelDisplayInit(ExynosDisplay *exynos_display, const std::string_view instance_str) {
37     ABinderProcess_setThreadPoolMaxThreadCount(0);
38 
39     std::shared_ptr<Display> display = ndk::SharedRefBase::make<Display>(exynos_display);
40     const std::string instance = std::string() + Display::descriptor + "/" + std::string(instance_str).c_str();
41     binder_status_t status =
42             AServiceManager_addService(display->asBinder().get(), instance.c_str());
43     LOG(INFO) << instance.c_str() << " service start...";
44     CHECK(status == STATUS_OK);
45 
46     ABinderProcess_startThreadPool();
47 }
48 
readCompensationImage(const aidl::android::hardware::common::NativeHandle & handle,const std::string & imageName)49 int32_t readCompensationImage(const aidl::android::hardware::common::NativeHandle &handle,
50                               const std::string &imageName) {
51     ALOGI("setCompensationImageHandle, imageName = %s", imageName.c_str());
52 
53     std::string shadowCompensationImage("/mnt/vendor/persist/display/");
54     shadowCompensationImage.append(imageName);
55 
56     native_handle_t *clone = makeFromAidl(handle);
57 
58     return load_png_image(shadowCompensationImage.c_str(), static_cast<buffer_handle_t>(clone));
59 }
60 
61 namespace aidl {
62 namespace com {
63 namespace google {
64 namespace hardware {
65 namespace pixel {
66 namespace display {
67 
68 // ----------------------------------------------------------------------------
69 
isHbmSupported(bool * _aidl_return)70 ndk::ScopedAStatus Display::isHbmSupported(bool *_aidl_return) {
71     *_aidl_return = false;
72     return ndk::ScopedAStatus::ok();
73 }
74 
setHbmState(HbmState state)75 ndk::ScopedAStatus Display::setHbmState(HbmState state) {
76     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
77 }
78 
getHbmState(HbmState * _aidl_return)79 ndk::ScopedAStatus Display::getHbmState(HbmState *_aidl_return) {
80     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
81 }
82 
isLbeSupported(bool * _aidl_return)83 ndk::ScopedAStatus Display::isLbeSupported(bool *_aidl_return) {
84     if (mDisplay) {
85         *_aidl_return = mDisplay->isLbeSupported();
86         return ndk::ScopedAStatus::ok();
87     }
88     *_aidl_return = false;
89     return ndk::ScopedAStatus::ok();
90 }
91 
setLbeState(LbeState state)92 ndk::ScopedAStatus Display::setLbeState(LbeState state) {
93     if (mDisplay) {
94         mDisplay->setLbeState(state);
95         return ndk::ScopedAStatus::ok();
96     }
97     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
98 }
99 
setLbeAmbientLight(int ambientLux)100 ndk::ScopedAStatus Display::setLbeAmbientLight(int ambientLux) {
101     if (mDisplay) {
102         mDisplay->setLbeAmbientLight(ambientLux);
103         return ndk::ScopedAStatus::ok();
104     }
105     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
106 }
107 
getLbeState(LbeState * _aidl_return)108 ndk::ScopedAStatus Display::getLbeState(LbeState *_aidl_return) {
109     if (mDisplay) {
110         *_aidl_return = mDisplay->getLbeState();
111         return ndk::ScopedAStatus::ok();
112     }
113     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
114 }
115 
isLhbmSupported(bool * _aidl_return)116 ndk::ScopedAStatus Display::isLhbmSupported(bool *_aidl_return) {
117     if (mDisplay) {
118         *_aidl_return = mDisplay->isLhbmSupported();
119         return ndk::ScopedAStatus::ok();
120     }
121     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
122 }
123 
setLhbmState(bool enabled)124 ndk::ScopedAStatus Display::setLhbmState(bool enabled) {
125     if (mDisplay && mDisplay->isLhbmSupported()) {
126         int32_t ret = mDisplay->setLhbmState(enabled);
127         if (!ret)
128             return ndk::ScopedAStatus::ok();
129         else if (ret == TIMED_OUT)
130             return ndk::ScopedAStatus::fromExceptionCode(STATUS_TIMED_OUT);
131     }
132     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
133 }
134 
getLhbmState(bool * _aidl_return)135 ndk::ScopedAStatus Display::getLhbmState(bool *_aidl_return) {
136     if (mDisplay && mDisplay->isLhbmSupported()) {
137         *_aidl_return = mDisplay->getLhbmState();
138         return ndk::ScopedAStatus::ok();
139     }
140     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
141 }
142 
setPeakRefreshRate(int rate)143 ndk::ScopedAStatus Display::setPeakRefreshRate(int rate) {
144     if (mDisplay && mDisplay->mOperationRateManager) {
145         mDisplay->mOperationRateManager->onPeakRefreshRate(rate);
146         return ndk::ScopedAStatus::ok();
147     }
148     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
149 }
150 
setLowPowerMode(bool enabled)151 ndk::ScopedAStatus Display::setLowPowerMode(bool enabled) {
152     if (mDisplay && mDisplay->mOperationRateManager) {
153         mDisplay->mOperationRateManager->onLowPowerMode(enabled);
154         return ndk::ScopedAStatus::ok();
155     }
156     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
157 }
158 
isOperationRateSupported(bool * _aidl_return)159 ndk::ScopedAStatus Display::isOperationRateSupported(bool *_aidl_return) {
160     if (mDisplay) {
161         *_aidl_return = mDisplay->isOperationRateSupported();
162         return ndk::ScopedAStatus::ok();
163     }
164     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
165 }
166 
setCompensationImageHandle(const NativeHandle & native_handle,const std::string & imageName,int * _aidl_return)167 ndk::ScopedAStatus Display::setCompensationImageHandle(const NativeHandle &native_handle,
168                                                        const std::string &imageName,
169                                                        int *_aidl_return) {
170     if (mDisplay && mDisplay->getPanelCalibrationStatus() == PanelCalibrationStatus::ORIGINAL) {
171         *_aidl_return = readCompensationImage(native_handle, imageName);
172     } else {
173         *_aidl_return = -1;
174     }
175     return ndk::ScopedAStatus::ok();
176 }
177 
setMinIdleRefreshRate(int fps,int * _aidl_return)178 ndk::ScopedAStatus Display::setMinIdleRefreshRate(int fps, int *_aidl_return) {
179     if (mDisplay) {
180         *_aidl_return = mDisplay->setMinIdleRefreshRate(fps, RrThrottleRequester::PIXEL_DISP);
181         return ndk::ScopedAStatus::ok();
182     }
183     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
184 }
185 
setRefreshRateThrottle(int delayMs,int * _aidl_return)186 ndk::ScopedAStatus Display::setRefreshRateThrottle(int delayMs, int *_aidl_return) {
187     if (mDisplay) {
188         if (delayMs < 0) {
189             *_aidl_return = BAD_VALUE;
190             ALOGW("%s fail: delayMs(%d) is less than 0", __func__, delayMs);
191             return ndk::ScopedAStatus::ok();
192         }
193 
194         *_aidl_return =
195                 mDisplay->setRefreshRateThrottleNanos(std::chrono::duration_cast<
196                                                               std::chrono::nanoseconds>(
197                                                               std::chrono::milliseconds(delayMs))
198                                                               .count(),
199                                                       RrThrottleRequester::PIXEL_DISP);
200         return ndk::ScopedAStatus::ok();
201     }
202     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
203 }
204 
runMediator(const RoiRect & roi,const Weight & weight,const HistogramPos & pos,std::vector<char16_t> * histogrambuffer)205 bool Display::runMediator(const RoiRect &roi, const Weight &weight, const HistogramPos &pos,
206                             std::vector<char16_t> *histogrambuffer) {
207     bool isConfigChanged;
208     histogram::HistogramMediator::HistogramConfig pendingConfig(roi, weight, pos);
209 
210     {
211         std::scoped_lock lock(mMediator.mConfigMutex);
212         isConfigChanged = mMediator.mConfig != pendingConfig;
213 
214         if (isConfigChanged) {
215             if (mMediator.setRoiWeightThreshold(roi, weight, pos) != HistogramErrorCode::NONE) {
216                 ALOGE("histogram error, SET_ROI_WEIGHT_THRESHOLD ERROR\n");
217                 return false;
218             }
219             mMediator.mConfig = pendingConfig;
220         }
221     }
222 
223     if (!mMediator.histRequested() &&
224         mMediator.requestHist() == HistogramErrorCode::ENABLE_HIST_ERROR) {
225         ALOGE("histogram error, ENABLE_HIST ERROR\n");
226     }
227 
228     /*
229      * DPU driver maintains always-on histogram engine state with up to date histogram data.
230      * Therefore we don't have explicitly to trigger onRefresh in case histogram configuration
231      * does not change.
232      */
233     if (isConfigChanged) {
234         mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
235     }
236 
237     if (mMediator.collectRoiLuma(histogrambuffer) != HistogramErrorCode::NONE) {
238         ALOGE("histogram error, COLLECT_ROI_LUMA ERROR\n");
239         return false;
240     }
241     return true;
242 }
243 
histogramSample(const RoiRect & roi,const Weight & weight,HistogramPos pos,Priority pri,std::vector<char16_t> * histogrambuffer,HistogramErrorCode * _aidl_return)244 ndk::ScopedAStatus Display::histogramSample(const RoiRect &roi, const Weight &weight,
245                                             HistogramPos pos, Priority pri,
246                                             std::vector<char16_t> *histogrambuffer,
247                                             HistogramErrorCode *_aidl_return) {
248     if (!mDisplay) {
249         ALOGI("mDisplay is NULL \n");
250         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
251     }
252     if (histogrambuffer == nullptr) {
253         ALOGE("histogrambuffer is null");
254         *_aidl_return = HistogramErrorCode::BAD_HIST_DATA;
255         return ndk::ScopedAStatus::ok();
256     }
257     if (mDisplay->isPowerModeOff() == true) {
258         *_aidl_return = HistogramErrorCode::DISPLAY_POWEROFF; // panel is off
259         return ndk::ScopedAStatus::ok();
260     }
261     if (mDisplay->isSecureContentPresenting() == true) {
262         *_aidl_return = HistogramErrorCode::DRM_PLAYING; // panel is playing DRM content
263         return ndk::ScopedAStatus::ok();
264     }
265     if ((roi.left < 0) || (roi.top < 0) || ((roi.right - roi.left) <= 0) ||
266         ((roi.bottom - roi.top) <= 0)) {
267         *_aidl_return = HistogramErrorCode::BAD_ROI;
268         ALOGE("histogram error, BAD_ROI (%d, %d, %d, %d) \n", roi.left, roi.top, roi.right,
269               roi.bottom);
270         return ndk::ScopedAStatus::ok();
271     }
272     if ((weight.weightR + weight.weightG + weight.weightB) != (histogram::WEIGHT_SUM)) {
273         *_aidl_return = HistogramErrorCode::BAD_WEIGHT;
274         ALOGE("histogram error, BAD_WEIGHT(%d, %d, %d)\n", weight.weightR, weight.weightG,
275               weight.weightB);
276         return ndk::ScopedAStatus::ok();
277     }
278     if (pos != HistogramPos::POST && pos != HistogramPos::PRE) {
279         *_aidl_return = HistogramErrorCode::BAD_POSITION;
280         ALOGE("histogram error, BAD_POSITION(%d)\n", (int)pos);
281         return ndk::ScopedAStatus::ok();
282     }
283     if (pri != Priority::NORMAL && pri != Priority::PRIORITY) {
284         *_aidl_return = HistogramErrorCode::BAD_PRIORITY;
285         ALOGE("histogram error, BAD_PRIORITY(%d)\n", (int)pri);
286         return ndk::ScopedAStatus::ok();
287     }
288     RoiRect roiCaled = mMediator.calRoi(roi); // fit roi coordinates to RRS
289     runMediator(roiCaled, weight, pos, histogrambuffer);
290     if (mDisplay->isSecureContentPresenting() == true) {
291         /* clear data to avoid leakage */
292         std::fill(histogrambuffer->begin(), histogrambuffer->end(), 0);
293         histogrambuffer->clear();
294         *_aidl_return = HistogramErrorCode::DRM_PLAYING; // panel is playing DRM content
295         return ndk::ScopedAStatus::ok();
296     }
297 
298     *_aidl_return = HistogramErrorCode::NONE;
299     return ndk::ScopedAStatus::ok();
300 }
301 
getPanelCalibrationStatus(PanelCalibrationStatus * _aidl_return)302 ndk::ScopedAStatus Display::getPanelCalibrationStatus(PanelCalibrationStatus *_aidl_return){
303     if (mDisplay) {
304         *_aidl_return = mDisplay->getPanelCalibrationStatus();
305         return ndk::ScopedAStatus::ok();
306     }
307     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
308 }
309 
isDbmSupported(bool * _aidl_return)310 ndk::ScopedAStatus Display::isDbmSupported(bool *_aidl_return) {
311     if (!mDisplay) {
312         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
313     }
314     *_aidl_return = mDisplay->isDbmSupported();
315     return ndk::ScopedAStatus::ok();
316 }
317 
setDbmState(bool enabled)318 ndk::ScopedAStatus Display::setDbmState(bool enabled) {
319     if (!mDisplay) {
320         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
321     }
322     mDisplay->setDbmState(enabled);
323     return ndk::ScopedAStatus::ok();
324 }
325 
getHistogramCapability(HistogramCapability * _aidl_return)326 ndk::ScopedAStatus Display::getHistogramCapability(HistogramCapability *_aidl_return) {
327     if (mDisplay && mDisplay->mHistogramController) {
328         return mDisplay->mHistogramController->getHistogramCapability(_aidl_return);
329     }
330     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
331 }
332 
registerHistogram(const ndk::SpAIBinder & token,const HistogramConfig & histogramConfig,HistogramErrorCode * _aidl_return)333 ndk::ScopedAStatus Display::registerHistogram(const ndk::SpAIBinder &token,
334                                               const HistogramConfig &histogramConfig,
335                                               HistogramErrorCode *_aidl_return) {
336     if (mDisplay && mDisplay->mHistogramController) {
337         return mDisplay->mHistogramController->registerHistogram(token, histogramConfig,
338                                                                  _aidl_return);
339     }
340     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
341 }
342 
queryHistogram(const ndk::SpAIBinder & token,std::vector<char16_t> * histogramBuffer,HistogramErrorCode * _aidl_return)343 ndk::ScopedAStatus Display::queryHistogram(const ndk::SpAIBinder &token,
344                                            std::vector<char16_t> *histogramBuffer,
345                                            HistogramErrorCode *_aidl_return) {
346     if (mDisplay && mDisplay->mHistogramController) {
347         return mDisplay->mHistogramController->queryHistogram(token, histogramBuffer, _aidl_return);
348     }
349     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
350 }
351 
reconfigHistogram(const ndk::SpAIBinder & token,const HistogramConfig & histogramConfig,HistogramErrorCode * _aidl_return)352 ndk::ScopedAStatus Display::reconfigHistogram(const ndk::SpAIBinder &token,
353                                               const HistogramConfig &histogramConfig,
354                                               HistogramErrorCode *_aidl_return) {
355     if (mDisplay && mDisplay->mHistogramController) {
356         return mDisplay->mHistogramController->reconfigHistogram(token, histogramConfig,
357                                                                  _aidl_return);
358     }
359     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
360 }
361 
unregisterHistogram(const ndk::SpAIBinder & token,HistogramErrorCode * _aidl_return)362 ndk::ScopedAStatus Display::unregisterHistogram(const ndk::SpAIBinder &token,
363                                                 HistogramErrorCode *_aidl_return) {
364     if (mDisplay && mDisplay->mHistogramController) {
365         return mDisplay->mHistogramController->unregisterHistogram(token, _aidl_return);
366     }
367     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
368 }
369 
setFixedTe2Rate(int rateHz,int * _aidl_return)370 ndk::ScopedAStatus Display::setFixedTe2Rate(int rateHz, int* _aidl_return) {
371     if (mDisplay) {
372         *_aidl_return = mDisplay->setFixedTe2Rate(rateHz);
373         return ndk::ScopedAStatus::ok();
374     }
375     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
376 }
377 
queryStats(DisplayStats::Tag tag,std::optional<DisplayStats> * _aidl_return)378 ndk::ScopedAStatus Display::queryStats(DisplayStats::Tag tag,
379                                        std::optional<DisplayStats>* _aidl_return) {
380     ATRACE_NAME(
381             String8::format("%s(%s)", __func__,
382                             aidl::com::google::hardware::pixel::display::toString(tag).c_str()));
383     if (!mDisplay) {
384         ALOGW("%s: mDisplay is NULL", __func__);
385         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
386     }
387     switch (tag) {
388         case DisplayStats::brightnessNits:
389             if (mDisplay->mBrightnessController != nullptr) {
390                 auto res = mDisplay->mBrightnessController->getBrightnessNitsAndMode();
391                 if (res != std::nullopt) {
392                     double nits = std::get<float>(res.value());
393                     (*_aidl_return) = DisplayStats::make<DisplayStats::brightnessNits>(nits);
394                 } else {
395                     ALOGW("%s: getBrightnessNitsAndMode returned nullopt!", __func__);
396                     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
397                 }
398             } else {
399                 ALOGW("%s: mBrightnessController is null!", __func__);
400                 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
401             }
402             break;
403         case DisplayStats::brightnessDbv:
404             if (mDisplay->mBrightnessController != nullptr) {
405                 int dbv = mDisplay->mBrightnessController->getBrightnessLevel();
406                 (*_aidl_return) = DisplayStats::make<DisplayStats::brightnessDbv>(dbv);
407             } else {
408                 ALOGW("%s: mBrightnessController is null!", __func__);
409                 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
410             }
411             break;
412         case DisplayStats::operationRate:
413             if (mDisplay->isOperationRateSupported()) {
414                 int op_hz = mDisplay->mOperationRateManager->getTargetOperationRate();
415                 (*_aidl_return) = DisplayStats::make<DisplayStats::operationRate>(op_hz);
416             } else {
417                 ALOGW("%s: operation rate not supported!", __func__);
418                 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
419             }
420             break;
421         case DisplayStats::opr:
422             if (mDisplay->mHistogramController) {
423                 std::array<double, HistogramController::kOPRConfigsCount> oprVals;
424                 ndk::ScopedAStatus status = mDisplay->mHistogramController->queryOPR(oprVals);
425                 if (!status.isOk()) return status;
426                 (*_aidl_return) = DisplayStats::make<DisplayStats::opr>(oprVals);
427             } else {
428                 ALOGW("%s: mHistogramController is null!", __func__);
429                 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
430             }
431             break;
432         default:
433             ALOGW("%s: invalid stats tag: %u", __func__, (uint32_t)tag);
434             *_aidl_return = std::nullopt;
435             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
436     };
437     return ndk::ScopedAStatus::ok();
438 }
439 
440 } // namespace display
441 } // namespace pixel
442 } // namespace hardware
443 } // namespace google
444 } // namespace com
445 } // namespace aidl
446