hwc: Handle validateAndSet failures in AD prepare call
When validateAndSet fails we must reset the mDoable flag to false and
close the fb device. This will prevent making a draw call using
invalid resource references and prevent any fd leaks.
Additionally, we should only turn AD on if there are no configuration
errors during prepare call. This will prevent toggling AD between
on/off state in the face of continuous failures.
Change-Id: I15502dbf64c6203092aa13e001bab5d27b0e17ec
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index fdf6e67..49e7e2a 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -41,37 +41,6 @@
using namespace overlay::utils;
namespace qhwc {
-//Opens writeback framebuffer and returns fd.
-static int openWbFb() {
- int wbFd = -1;
- //Check opening which FB would connect LM to WB
- const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
- if(wbFbNum >= 0) {
- char wbFbPath[256];
- snprintf (wbFbPath, sizeof(wbFbPath),
- "/sys/class/graphics/fb%d", wbFbNum);
- //Opening writeback fb first time would create ad node if the device
- //supports adaptive display
- wbFd = open(wbFbPath, O_RDONLY);
- if(wbFd < 0) {
- ALOGE("%s: Failed to open /sys/class/graphics/fb%d with error %s",
- __func__, wbFbNum, strerror(errno));
- }
- } else {
- ALOGD_IF(DEBUG, "%s: No writeback available", __func__);
- }
- return wbFd;
-}
-
-static inline void closeWbFb(int& fd) {
- if(fd >= 0) {
- close(fd);
- fd = -1;
- } else {
- ALOGE("%s: Invalid fd %d", __func__, fd);
- }
-}
-
//Helper to write data to ad node
static void adWrite(const int& value) {
const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
@@ -124,32 +93,31 @@
return ret;
}
-AssertiveDisplay::AssertiveDisplay(hwc_context_t *ctx) : mWbFd(-1),
- mDoable(false), mFeatureEnabled(false),
- mDest(overlay::utils::OV_INVALID) {
- int fd = openWbFb();
- if(fd >= 0) {
- //Values in ad node:
- //-1 means feature is disabled on device
- // 0 means feature exists but turned off, will be turned on by hwc
- // 1 means feature is turned on by hwc
- // Plus, we do this feature only on split primary displays.
- // Plus, we do this feature only if ro.qcom.ad=2
+AssertiveDisplay::AssertiveDisplay(hwc_context_t *ctx) :
+ mTurnedOff(true), mFeatureEnabled(false),
+ mDest(overlay::utils::OV_INVALID)
+{
+ //Values in ad node:
+ //-1 means feature is disabled on device
+ // 0 means feature exists but turned off, will be turned on by hwc
+ // 1 means feature is turned on by hwc
+ // Plus, we do this feature only on split primary displays.
+ // Plus, we do this feature only if ro.qcom.ad=2
- char property[PROPERTY_VALUE_MAX];
- const int ENABLED = 2;
- int val = 0;
+ char property[PROPERTY_VALUE_MAX];
+ const int ENABLED = 2;
+ int val = 0;
- if(property_get("ro.qcom.ad", property, "0") > 0) {
- val = atoi(property);
- }
+ if(property_get("ro.qcom.ad", property, "0") > 0) {
+ val = atoi(property);
+ }
- if(adRead() >= 0 && isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY) &&
- val == ENABLED) {
- ALOGD_IF(DEBUG, "Assertive display feature supported");
- mFeatureEnabled = true;
- }
- closeWbFb(fd);
+ if(adRead() >= 0 && isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY) &&
+ val == ENABLED) {
+ ALOGD_IF(DEBUG, "Assertive display feature supported");
+ mFeatureEnabled = true;
+ // If feature exists but is turned off, set mTurnedOff to true
+ mTurnedOff = adRead() > 0 ? false : true;
}
}
@@ -168,17 +136,24 @@
}
}
+void AssertiveDisplay::turnOffAD() {
+ if(mFeatureEnabled) {
+ if(!mTurnedOff) {
+ const int off = 0;
+ adWrite(off);
+ mTurnedOff = true;
+ }
+ }
+ mDoable = false;
+}
+
bool AssertiveDisplay::prepare(hwc_context_t *ctx,
const hwc_rect_t& crop,
const Whf& whf,
const private_handle_t *hnd) {
if(!isDoable()) {
- if(isModeOn()) {
- //Cleanup one time during this switch
- const int off = 0;
- adWrite(off);
- closeWbFb(mWbFd);
- }
+ //Cleanup one time during this switch
+ turnOffAD();
return false;
}
@@ -246,27 +221,30 @@
}
mDest = dest;
- if(!isModeOn()) {
- mWbFd = openWbFb();
- if(mWbFd >= 0) {
- //write to sysfs, one time during this switch
- const int on = 1;
- adWrite(on);
- }
- }
-
- if(!ctx->mOverlay->validateAndSet(overlay::Overlay::DPY_WRITEBACK,
- mWbFd)) {
+ int wbFd = wb->getFbFd();
+ if(mFeatureEnabled && wbFd >= 0 &&
+ !ctx->mOverlay->validateAndSet(overlay::Overlay::DPY_WRITEBACK, wbFd))
+ {
ALOGE("%s: Failed to validate and set overlay for dpy %d"
,__FUNCTION__, overlay::Overlay::DPY_WRITEBACK);
+ turnOffAD();
return false;
}
+ // Only turn on AD if there are no errors during configuration stage
+ // and if it was previously in OFF state.
+ if(mFeatureEnabled && mTurnedOff) {
+ //write to sysfs, one time during this switch
+ const int on = 1;
+ adWrite(on);
+ mTurnedOff = false;
+ }
+
return true;
}
bool AssertiveDisplay::draw(hwc_context_t *ctx, int fd, uint32_t offset) {
- if(!isDoable() || !isModeOn()) {
+ if(!isDoable()) {
return false;
}