hwc2: Parameter validation and bounds checks

  - Introduce use of GetDozeSupport

Change-Id: Ic7edcd14b0c390fbd58f6be05b983a40b75c90eb
CRs-Fixed: 2114346
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index e90dbdd..1555b1b 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -160,7 +160,7 @@
   int GetVisibleDisplayRect(hwc_rect_t *rect);
   void BuildLayerStack(void);
   void BuildSolidFillStack(void);
-  HWCLayer *GetHWCLayer(hwc2_layer_t layer);
+  HWCLayer *GetHWCLayer(hwc2_layer_t layer_id);
   void ResetValidation() { validated_ = false; }
   uint32_t GetGeometryChanges() { return geometry_changes_; }
 
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index fee67b4..13a67cf 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -406,8 +406,13 @@
 }
 
 HWC2::Error HWCLayer::SetLayerPlaneAlpha(float alpha) {
-  // Conversion of float alpha in range 0.0 to 1.0 similar to the HWC Adapter
+  if (alpha < 0.0f || alpha > 1.0f) {
+    return HWC2::Error::BadParameter;
+  }
+
+  //  Conversion of float alpha in range 0.0 to 1.0 similar to the HWC Adapter
   uint8_t plane_alpha = static_cast<uint8_t>(std::round(255.0f * alpha));
+
   if (layer_->plane_alpha != plane_alpha) {
     geometry_changes_ |= kPlaneAlpha;
     layer_->plane_alpha = plane_alpha;
@@ -457,8 +462,10 @@
       layer_transform.flip_vertical = true;
       break;
     case HWC2::Transform::None:
-      // do nothing
       break;
+    default:
+      //  bad transform
+      return HWC2::Error::BadParameter;
   }
 
   if (layer_transform_ != layer_transform) {
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 390f39e..fa5bce0 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -483,14 +483,20 @@
 }
 
 static int32_t GetDozeSupport(hwc2_device_t *device, hwc2_display_t display, int32_t *out_support) {
+  if (!device || !out_support) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
+    return HWC2_ERROR_BAD_DISPLAY;
+  }
+
   if (display == HWC_DISPLAY_PRIMARY) {
     *out_support = 1;
   } else {
-    // TODO(user): Port over connect_display_ from HWC1
-    // Return no error for connected displays
     *out_support = 0;
-    return HWC2_ERROR_BAD_DISPLAY;
   }
+
   return HWC2_ERROR_NONE;
 }
 
@@ -663,14 +669,19 @@
 
 int32_t HWCSession::SetLayerZOrder(hwc2_device_t *device, hwc2_display_t display,
                                    hwc2_layer_t layer, uint32_t z) {
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
+    return HWC2_ERROR_BAD_DISPLAY;
+  }
+
   SCOPE_LOCK(locker_[display]);
+
   return CallDisplayFunction(device, display, &HWCDisplay::SetLayerZOrder, layer, z);
 }
 
 int32_t HWCSession::SetOutputBuffer(hwc2_device_t *device, hwc2_display_t display,
                                     buffer_handle_t buffer, int32_t releaseFence) {
   if (!device) {
-    return HWC2_ERROR_BAD_DISPLAY;
+    return HWC2_ERROR_BAD_PARAMETER;
   }
 
   if (display != HWC_DISPLAY_VIRTUAL) {
@@ -689,24 +700,51 @@
 }
 
 int32_t HWCSession::SetPowerMode(hwc2_device_t *device, hwc2_display_t display, int32_t int_mode) {
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
+    return HWC2_ERROR_BAD_DISPLAY;
+  }
+
+  //  validate device and also avoid undefined behavior in cast to HWC2::PowerMode
+  if (!device || int_mode < HWC2_POWER_MODE_OFF || int_mode > HWC2_POWER_MODE_DOZE_SUSPEND) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+
   auto mode = static_cast<HWC2::PowerMode>(int_mode);
+
+  //  all displays support on/off. Check for doze modes
+  int support = 0;
+  GetDozeSupport(device, display, &support);
+  if (!support && (mode == HWC2::PowerMode::Doze || mode == HWC2::PowerMode::DozeSuspend)) {
+    return HWC2_ERROR_UNSUPPORTED;
+  }
+
   SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
   return CallDisplayFunction(device, display, &HWCDisplay::SetPowerMode, mode);
 }
 
 static int32_t SetVsyncEnabled(hwc2_device_t *device, hwc2_display_t display, int32_t int_enabled) {
+  //  avoid undefined behavior in cast to HWC2::Vsync
+  if (int_enabled < HWC2_VSYNC_INVALID || int_enabled > HWC2_VSYNC_DISABLE) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+
   auto enabled = static_cast<HWC2::Vsync>(int_enabled);
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetVsyncEnabled, enabled);
 }
 
 int32_t HWCSession::ValidateDisplay(hwc2_device_t *device, hwc2_display_t display,
                                     uint32_t *out_num_types, uint32_t *out_num_requests) {
-  DTRACE_SCOPED();
-  HWCSession *hwc_session = static_cast<HWCSession *>(device);
+  //  out_num_types and out_num_requests will be non-NULL
   if (!device) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+
+  if (display >= HWC_NUM_DISPLAY_TYPES) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
 
+  DTRACE_SCOPED();
+  HWCSession *hwc_session = static_cast<HWCSession *>(device);
   // TODO(user): Handle secure session, handle QDCM solid fill
   // Handle external_pending_connect_ in CreateVirtualDisplay
   auto status = HWC2::Error::BadDisplay;
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 3659370..df58093 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -99,6 +99,10 @@
                                    hwc2_layer_t layer, HWC2::Error (HWCLayer::*member)(Args...),
                                    Args... args) {
     if (!device) {
+      return HWC2_ERROR_BAD_PARAMETER;
+    }
+
+    if (display >= HWC_NUM_DISPLAY_TYPES) {
       return HWC2_ERROR_BAD_DISPLAY;
     }
 
diff --git a/sdm/libs/hwc2/hwc_session_services.cpp b/sdm/libs/hwc2/hwc_session_services.cpp
index a5cf66a..52eaf7a 100644
--- a/sdm/libs/hwc2/hwc_session_services.cpp
+++ b/sdm/libs/hwc2/hwc_session_services.cpp
@@ -94,22 +94,25 @@
                                             isDisplayConnected_cb _hidl_cb) {
   int32_t error = -EINVAL;
   bool connected = false;
-
   int disp_id = MapDisplayType(dpy);
-  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
 
-  if (disp_id >= 0) {
-    connected = hwc_display_[disp_id];
-    error = 0;
+  if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
+    _hidl_cb(error, connected);
+    return Void();
   }
 
-  _hidl_cb(error, connected);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
 
+  connected = hwc_display_[disp_id];
+  error = 0;
+
+  _hidl_cb(error, connected);
   return Void();
 }
 
 int32_t HWCSession::SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) {
-  if (disp_id < 0) {
+  if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
+    DLOGE("Invalid display = %d", disp_id);
     return -EINVAL;
   }