graphics: really reset HWC2 on SF crashes

Perform a final presentDisplay to clear the screen and get HWC2 out
of any special state (e.g., some implementations put themselves in
special states between validateDisplay and presentDisplay).  Our
only portable choice really is to abort(), but that is not an option
because we have other clients such as VTS or VR.

Bug: 35872161
Test: manual
Change-Id: I9028705607d1b86d418a379c6e90e833d638b3f5
diff --git a/graphics/composer/2.1/default/ComposerClient.cpp b/graphics/composer/2.1/default/ComposerClient.cpp
index 72ba8f8..0114430 100644
--- a/graphics/composer/2.1/default/ComposerClient.cpp
+++ b/graphics/composer/2.1/default/ComposerClient.cpp
@@ -230,30 +230,69 @@
 
 ComposerClient::~ComposerClient()
 {
-    ALOGD("client destroyed");
+    // We want to call hwc2_close here (and move hwc2_open to the
+    // constructor), with the assumption that hwc2_close would
+    //
+    //  - clean up all resources owned by the client
+    //  - make sure all displays are blank (since there is no layer)
+    //
+    // But since SF used to crash at this point, different hwcomposer2
+    // implementations behave differently on hwc2_close.  Our only portable
+    // choice really is to abort().  But that is not an option anymore
+    // because we might also have VTS or VR as clients that can come and go.
+    //
+    // Below we manually clean all resources (layers and virtual
+    // displays), and perform a presentDisplay afterwards.
+    ALOGW("destroying composer client");
 
     mHal.enableCallback(false);
-    mHal.removeClient();
 
-    // no need to grab the mutex as any in-flight hwbinder call should keep
-    // the client alive
+    // no need to grab the mutex as any in-flight hwbinder call would have
+    // kept the client alive
     for (const auto& dpy : mDisplayData) {
-        if (!dpy.second.Layers.empty()) {
-            ALOGW("client destroyed with valid layers");
-        }
+        ALOGW("destroying client resources for display %" PRIu64, dpy.first);
+
         for (const auto& ly : dpy.second.Layers) {
             mHal.destroyLayer(dpy.first, ly.first);
         }
 
         if (dpy.second.IsVirtual) {
-            ALOGW("client destroyed with valid virtual display");
             mHal.destroyVirtualDisplay(dpy.first);
+        } else {
+            ALOGW("performing a final presentDisplay");
+
+            std::vector<Layer> changedLayers;
+            std::vector<IComposerClient::Composition> compositionTypes;
+            uint32_t displayRequestMask = 0;
+            std::vector<Layer> requestedLayers;
+            std::vector<uint32_t> requestMasks;
+            mHal.validateDisplay(dpy.first, &changedLayers, &compositionTypes,
+                    &displayRequestMask, &requestedLayers, &requestMasks);
+
+            mHal.acceptDisplayChanges(dpy.first);
+
+            int32_t presentFence = -1;
+            std::vector<Layer> releasedLayers;
+            std::vector<int32_t> releaseFences;
+            mHal.presentDisplay(dpy.first, &presentFence, &releasedLayers, &releaseFences);
+            if (presentFence >= 0) {
+                close(presentFence);
+            }
+            for (auto fence : releaseFences) {
+                if (fence >= 0) {
+                    close(fence);
+                }
+            }
         }
     }
 
     mDisplayData.clear();
 
     sHandleImporter.cleanup();
+
+    mHal.removeClient();
+
+    ALOGW("removed composer client");
 }
 
 void ComposerClient::initialize()