sf: Fixes for resolution change in SurfaceFlinger

1. Use active config from HWC when querying display attributes

   When we query the display attributes we should use the active
   config as reported by HWC in cases where HWC version is 1.4.
   In all other cases we should revert to the default config,
   config 0, as the active config.

2. Set/update the display config if HWC config change was successful

   The new config should only be applied if HWC succeeded in changing
   the active config. This would otherwise cause failure or undefined
   behavior if the client sets an invalid/unsupported display config.

3. Set the active config at display creation time

   When a new display device is added update the active config by
   querying HWC.

Change-Id: If55b9b308750f17bb44eab555d17e31972bc3968
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index fa9e662..aa0ceb2 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -372,7 +372,12 @@
         return err;
     }
 
-    mDisplayData[disp].currentConfig = 0;
+    int currentConfig = getActiveConfig(disp);
+    if (currentConfig < 0 || currentConfig > (numConfigs-1)) {
+        ALOGE("%s: Invalid display config! %d", __FUNCTION__, currentConfig);
+        currentConfig = 0;
+    }
+    mDisplayData[disp].currentConfig = currentConfig;
     for (size_t c = 0; c < numConfigs; ++c) {
         err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
                 DISPLAY_ATTRIBUTES, values);
@@ -853,15 +858,31 @@
 status_t HWComposer::setActiveConfig(int disp, int mode) {
     LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE);
     DisplayData& dd(mDisplayData[disp]);
-    dd.currentConfig = mode;
     if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
-        return (status_t)mHwc->setActiveConfig(mHwc, disp, mode);
+        status_t status = static_cast<status_t>(
+                mHwc->setActiveConfig(mHwc, disp, mode));
+        if (status == NO_ERROR) {
+            dd.currentConfig = mode;
+        } else {
+            ALOGE("%s Failed to set new config (%d) for display (%d)",
+                    __FUNCTION__, mode, disp);
+        }
+        return status;
     } else {
         LOG_FATAL_IF(mode != 0);
     }
     return NO_ERROR;
 }
 
+int HWComposer::getActiveConfig(int disp) const {
+    LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE);
+    if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
+        return mHwc->getActiveConfig(mHwc, disp);
+    } else {
+        return 0;
+    }
+}
+
 void HWComposer::disconnectDisplay(int disp) {
     LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY);
     DisplayData& dd(mDisplayData[disp]);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 2d76ef1..97e03fb 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -105,6 +105,9 @@
     // set active config
     status_t setActiveConfig(int disp, int mode);
 
+    // get active config
+    int getActiveConfig(int disp) const;
+
     // reset state when an external, non-virtual display is disconnected
     void disconnectDisplay(int disp);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e379bf6..5e58899 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -662,8 +662,10 @@
         return;
     }
 
-    hw->setActiveConfig(mode);
-    getHwComposer().setActiveConfig(type, mode);
+    status_t status = getHwComposer().setActiveConfig(type, mode);
+    if (status == NO_ERROR) {
+        hw->setActiveConfig(mode);
+    }
 }
 
 status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
@@ -1605,6 +1607,13 @@
                         hw->setProjection(state.orientation,
                                 state.viewport, state.frame);
                         hw->setDisplayName(state.displayName);
+                        // When a new display device is added update the active
+                        // config by querying HWC otherwise the default config
+                        // (config 0) will be used.
+                        int activeConfig = mHwc->getActiveConfig(hwcDisplayId);
+                        if (activeConfig >= 0) {
+                            hw->setActiveConfig(activeConfig);
+                        }
                         mDisplays.add(display, hw);
                         if (state.isVirtualDisplay()) {
                             if (hwcDisplayId >= 0) {