Improved sanity checks for the hwcomposer

- Adds the LOG_TAG macro
- Checks for empty composition requests (no layers)
- Adds exception for compostion request with only FB target with null
  handle
- Switches to LOG_ALWAYS_FATAL for fatal crashes

(Taken from Change-Id: Icb35eab7b0862485bf4b3d9fa02f71aec1220a0c)

Bug: 72998203
Test: local
Change-Id: Ia66ee481decbae204304852c8fb45260cb79f6a1
diff --git a/guest/hals/hwcomposer/legacy/hwcomposer.cpp b/guest/hals/hwcomposer/legacy/hwcomposer.cpp
index 5e41e00..565c09c 100644
--- a/guest/hals/hwcomposer/legacy/hwcomposer.cpp
+++ b/guest/hals/hwcomposer/legacy/hwcomposer.cpp
@@ -22,6 +22,8 @@
 // to support 1.1 implementations it can be copied into cuttlefish from
 // frameworks/native/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.*
 
+#define LOG_TAG "hwc.cf_x86"
+
 #include <guest/libs/platform_support/api_level_fixes.h>
 
 #include <errno.h>
@@ -37,6 +39,8 @@
 #include <sys/resource.h>
 #include <sys/time.h>
 
+#include <string>
+
 #define HWC_REMOVE_DEPRECATED_VERSIONS 1
 
 #include <cutils/compiler.h>
@@ -84,11 +88,44 @@
 
 namespace {
 
+std::string CompositionString(int type) {
+  switch (type) {
+    case HWC_FRAMEBUFFER:
+      return "Framebuffer";
+    case HWC_OVERLAY:
+      return "Overlay";
+    case HWC_BACKGROUND:
+      return "Background";
+    case HWC_FRAMEBUFFER_TARGET:
+      return "FramebufferTarget";
+    case HWC_SIDEBAND:
+      return "Sideband";
+    case HWC_CURSOR_OVERLAY:
+      return "CursorOverlay";
+    default:
+      return std::string("Unknown (") + std::to_string(type) + ")";
+  }
+}
+
+void LogLayers(int num_layers, vsoc_hwc_layer* layers, int invalid) {
+  ALOGE("Layers:");
+  for (int idx = 0; idx < num_layers; ++idx) {
+    std::string log_line;
+    if (idx == invalid) {
+      log_line = "Invalid layer: ";
+    }
+    log_line +=
+        "Composition Type: " + CompositionString(layers[idx].compositionType);
+    ALOGE("%s", log_line.c_str());
+  }
+}
+
 // Ensures that the layer does not include any inconsistencies
 bool IsValidLayer(const vsoc_hwc_layer& layer) {
   if (layer.flags & HWC_SKIP_LAYER) {
-    // A layer we are asked to skip is valid regardless of its contents
-    return true;
+    // A layer we are asked to skip validate should not be marked as skip
+    ALOGE("%s: Layer is marked as skip", __FUNCTION__);
+    return false;
   }
   // Check displayFrame
   if (layer.displayFrame.left > layer.displayFrame.right ||
@@ -132,12 +169,24 @@
   return true;
 }
 
-bool IsValidComposition(int num_layers, vsoc_hwc_layer* layers) {
-  // The FRAMEBUFFER_TARGET layer needs to be sane only if there is at least one
-  // layer marked HWC_FRAMEBUFFER or if there is no layer marked HWC_OVERLAY
-  // (i.e some layers where composed with OpenGL, no layer marked overlay or
-  // framebuffer means that surfaceflinger decided to go for OpenGL without
-  // asking the hwcomposer first)
+bool IsValidComposition(int num_layers, vsoc_hwc_layer* layers, bool on_set) {
+  if (num_layers == 0) {
+    ALOGE("Composition requested with 0 layers");
+    return false;
+  }
+  // Sometimes the hwcomposer receives a prepare and set calls with no other
+  // layer than the FRAMEBUFFER_TARGET with a null handler. We treat this case
+  // independently as a valid composition, but issue a warning about it.
+  if (num_layers == 1 && layers[0].compositionType == HWC_FRAMEBUFFER_TARGET &&
+      layers[0].handle == NULL) {
+    ALOGW("Received request for empty composition, treating as valid noop");
+    return true;
+  }
+  // The FRAMEBUFFER_TARGET layer needs to be sane only if
+  // there is at least one layer marked HWC_FRAMEBUFFER or if there is no layer
+  // marked HWC_OVERLAY (i.e some layers where composed with OpenGL, no layer
+  // marked overlay or framebuffer means that surfaceflinger decided to go for
+  // OpenGL without asking the hwcomposer first)
   bool check_fb_target = true;
   for (int idx = 0; idx < num_layers; ++idx) {
     if (layers[idx].compositionType == HWC_FRAMEBUFFER) {
@@ -155,13 +204,19 @@
   for (int idx = 0; idx < num_layers; ++idx) {
     switch (layers[idx].compositionType) {
     case HWC_FRAMEBUFFER_TARGET:
-      if (check_fb_target && !IsValidLayer(layers[idx])) {
+      // In the call to prepare() the framebuffer target does not have a valid
+      // buffer_handle, so we don't validate it yet.
+      if (on_set && check_fb_target && !IsValidLayer(layers[idx])) {
+        ALOGE("%s: Invalid layer found", __FUNCTION__);
+        LogLayers(num_layers, layers, idx);
         return false;
       }
       break;
     case HWC_OVERLAY:
       if (!(layers[idx].flags & HWC_SKIP_LAYER) &&
           !IsValidLayer(layers[idx])) {
+        ALOGE("%s: Invalid layer found", __FUNCTION__);
+        LogLayers(num_layers, layers, idx);
         return false;
       }
       break;
@@ -183,8 +238,8 @@
 
   if (!list) return 0;
 #endif
-  if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0])) {
-    LOG_FATAL("%s: Invalid composition requested", __FUNCTION__);
+  if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], false)) {
+    LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
     return -1;
   }
   reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)->composer->PrepareLayers(
@@ -195,8 +250,13 @@
 #if VSOC_PLATFORM_SDK_BEFORE(J_MR1)
 int vsoc_hwc_set(struct hwc_composer_device* dev, hwc_display_t dpy,
                  hwc_surface_t sur, hwc_layer_list_t* list) {
-  if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0])) {
-    LOG_FATAL("%s: Invalid composition requested", __FUNCTION__);
+  if (list->numHwLayers == 1 &&
+      layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) {
+    ALOGW("Received request for empty composition, treating as valid noop");
+    return 0;
+  }
+  if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], true)) {
+    LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
     return -1;
   }
   return reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)
@@ -211,8 +271,13 @@
   if (!contents) return 0;
 
   vsoc_hwc_layer* layers = &contents->hwLayers[0];
-  if (!IsValidComposition(contents->numHwLayers, layers)) {
-    LOG_FATAL("%s: Invalid composition requested", __FUNCTION__);
+  if (contents->numHwLayers == 1 &&
+      layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) {
+    ALOGW("Received request for empty composition, treating as valid noop");
+    return 0;
+  }
+  if (!IsValidComposition(contents->numHwLayers, layers, true)) {
+    LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
     return -1;
   }
   int retval =