hwc2: Clean-up asynchronous power mode set

* Avoid blocking wait when checking for secure session.
* Add power state to dummy display.
* Restore exact power mode on ending secure session.

Change-Id: I74fab8fadb8528a15e32aa96b0362ad386bd30cc
CRs-Fixed: 2449460
diff --git a/composer/hwc_display.cpp b/composer/hwc_display.cpp
index 10a9a75..366d5c6 100644
--- a/composer/hwc_display.cpp
+++ b/composer/hwc_display.cpp
@@ -2079,6 +2079,7 @@
 
   if (active_secure_sessions_[kSecureDisplay] != secure_sessions[kSecureDisplay]) {
     if (secure_sessions[kSecureDisplay]) {
+      pending_power_mode_ = current_power_mode_;
       HWC2::Error error = SetPowerMode(HWC2::PowerMode::Off, true /* teardown */);
       if (error != HWC2::Error::None) {
         DLOGE("SetPowerMode failed. Error = %d", error);
@@ -2087,9 +2088,9 @@
       *power_on_pending = true;
     }
 
-    DLOGI("SecureDisplay state changed from %d to %d for display %d",
+    DLOGI("SecureDisplay state changed from %d to %d for display %d-%d",
           active_secure_sessions_.test(kSecureDisplay), secure_sessions.test(kSecureDisplay),
-          type_);
+          id_, type_);
   }
   active_secure_sessions_ = secure_sessions;
   return 0;
diff --git a/composer/hwc_display.h b/composer/hwc_display.h
index 4baa778..9a0f9e7 100644
--- a/composer/hwc_display.h
+++ b/composer/hwc_display.h
@@ -356,6 +356,12 @@
   virtual void GetLayerStack(HWCLayerStack *stack);
   virtual void SetLayerStack(HWCLayerStack *stack);
   virtual void PostPowerMode();
+  virtual HWC2::PowerMode GetPendingPowerMode() {
+    return pending_power_mode_;
+  };
+  virtual void ClearPendingPowerMode() {
+    pending_power_mode_ = current_power_mode_;
+  };
 
  protected:
   static uint32_t throttling_refresh_rate_;
@@ -415,6 +421,7 @@
   uint32_t dump_frame_index_ = 0;
   bool dump_input_layers_ = false;
   HWC2::PowerMode current_power_mode_ = HWC2::PowerMode::Off;
+  HWC2::PowerMode pending_power_mode_ = HWC2::PowerMode::Off;
   bool swap_interval_zero_ = false;
   bool display_paused_ = false;
   uint32_t min_refresh_rate_ = 0;
diff --git a/composer/hwc_display_builtin.cpp b/composer/hwc_display_builtin.cpp
index 40a3ac3..d3e8785 100644
--- a/composer/hwc_display_builtin.cpp
+++ b/composer/hwc_display_builtin.cpp
@@ -127,6 +127,8 @@
     DLOGI("Drop redundant drawcycles %d", id_);
   }
 
+  is_primary_ = display_intf_->IsPrimaryDisplay();
+
   return status;
 }
 
@@ -136,7 +138,7 @@
 
   DTRACE_SCOPED();
 
-  if (display_paused_) {
+  if (display_paused_ || (!is_primary_ && active_secure_sessions_[kSecureDisplay])) {
     MarkLayersForGPUBypass();
     return status;
   }
@@ -244,7 +246,10 @@
   auto status = HWC2::Error::None;
 
   DTRACE_SCOPED();
-  if (display_paused_) {
+
+  if (!is_primary_ && active_secure_sessions_[kSecureDisplay]) {
+      return status;
+  } else if (display_paused_) {
     DisplayError error = display_intf_->Flush(&layer_stack_);
     validated_ = false;
     if (error != kErrorNone) {
@@ -594,6 +599,10 @@
     return -EINVAL;
   }
 
+  if (!is_primary_) {
+    return HWCDisplay::HandleSecureSession(secure_sessions, power_on_pending);
+  }
+
   if (current_power_mode_ != HWC2::PowerMode::On) {
     return 0;
   }
@@ -607,9 +616,9 @@
       return err;
     }
 
-    DLOGI("SecureDisplay state changed from %d to %d for display %d",
+    DLOGI("SecureDisplay state changed from %d to %d for display %d-%d",
           active_secure_sessions_.test(kSecureDisplay), secure_sessions.test(kSecureDisplay),
-          type_);
+          id_, type_);
   }
   active_secure_sessions_ = secure_sessions;
   *power_on_pending = false;
diff --git a/composer/hwc_display_builtin.h b/composer/hwc_display_builtin.h
index fa0b859..0047ae9 100644
--- a/composer/hwc_display_builtin.h
+++ b/composer/hwc_display_builtin.h
@@ -139,6 +139,7 @@
   // Members for 1 frame capture in a client provided buffer
   bool frame_capture_buffer_queued_ = false;
   int frame_capture_status_ = -EAGAIN;
+  bool is_primary_ = false;
 };
 
 }  // namespace sdm
diff --git a/composer/hwc_display_dummy.cpp b/composer/hwc_display_dummy.cpp
index fac6370..eff0ed6 100644
--- a/composer/hwc_display_dummy.cpp
+++ b/composer/hwc_display_dummy.cpp
@@ -82,4 +82,9 @@
   return HWC2::Error::None;
 }
 
+HWC2::Error HWCDisplayDummy::UpdatePowerMode(HWC2::PowerMode mode) {
+  current_power_mode_ = mode;
+  return HWC2::Error::None;
+}
+
 }  // namespace sdm
diff --git a/composer/hwc_display_dummy.h b/composer/hwc_display_dummy.h
index 29e04f4..bf28a03 100644
--- a/composer/hwc_display_dummy.h
+++ b/composer/hwc_display_dummy.h
@@ -45,6 +45,7 @@
   virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
   virtual HWC2::Error Present(int32_t *out_retire_fence);
   virtual HWC2::Error GetActiveConfig(hwc2_config_t *out_config);
+  virtual HWC2::Error UpdatePowerMode(HWC2::PowerMode mode);
 
  private:
   HWCDisplayDummy(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
diff --git a/composer/hwc_session.cpp b/composer/hwc_session.cpp
index 6af6b16..b09a6e9 100644
--- a/composer/hwc_session.cpp
+++ b/composer/hwc_session.cpp
@@ -55,7 +55,7 @@
 
 static HWCUEvent g_hwc_uevent_;
 Locker HWCSession::locker_[HWCCallbacks::kNumDisplays];
-bool HWCSession::power_on_pending_[HWCCallbacks::kNumDisplays];
+bool HWCSession::pending_power_mode_[HWCCallbacks::kNumDisplays];
 Locker HWCSession::power_state_[HWCCallbacks::kNumDisplays];
 Locker HWCSession::display_config_locker_;
 static const int kSolidFillDelay = 100 * 1000;
@@ -179,7 +179,7 @@
     g_hwc_uevent_.Register(this);
   }
 
-  int value = 0;
+  int value = 1;  // Default value when property is not present.
   Debug::Get()->GetProperty(ENABLE_ASYNC_POWERMODE, &value);
   async_powermode_ = (value == 1);
   DLOGI("builtin_powermode_override: %d", async_powermode_);
@@ -621,18 +621,22 @@
   }
 
   HandleSecureSession();
+
+
+  hwc2_display_t target_display = display;
+
   {
     SCOPE_LOCK(power_state_[display]);
     if (power_state_transition_[display]) {
       // Route all interactions with client to dummy display.
-      display = map_hwc_display_.find(display)->second;
+      target_display = map_hwc_display_.find(display)->second;
     }
   }
 
   {
-    SEQUENCE_EXIT_SCOPE_LOCK(locker_[display]);
-    if (!hwc_display_[display]) {
-      DLOGW("Removed Display : display = %" PRIu64, display);
+    SEQUENCE_EXIT_SCOPE_LOCK(locker_[target_display]);
+    if (!hwc_display_[target_display]) {
+      DLOGW("Removed Display : display = %" PRIu64, target_display);
       return HWC2_ERROR_BAD_DISPLAY;
     }
 
@@ -640,27 +644,27 @@
       return HWC2_ERROR_BAD_PARAMETER;
     }
 
-    if (power_on_pending_[display]) {
+    if (pending_power_mode_[display]) {
       status = HWC2::Error::None;
     } else {
-      status = PresentDisplayInternal(display, out_retire_fence);
+      status = PresentDisplayInternal(target_display, out_retire_fence);
       if (status == HWC2::Error::None) {
         // Check if hwc's refresh trigger is getting exercised.
         if (callbacks_.NeedsRefresh(display)) {
-          hwc_display_[display]->SetPendingRefresh();
+          hwc_display_[target_display]->SetPendingRefresh();
           callbacks_.ResetRefresh(display);
         }
-        status = hwc_display_[display]->Present(out_retire_fence);
+        status = hwc_display_[target_display]->Present(out_retire_fence);
       }
     }
   }
 
   if (status != HWC2::Error::None && status != HWC2::Error::NotValidated) {
-    SEQUENCE_CANCEL_SCOPE_LOCK(locker_[display]);
+    SEQUENCE_CANCEL_SCOPE_LOCK(locker_[target_display]);
   }
 
-  HandlePowerOnPending(display, *out_retire_fence);
-  HandleHotplugPending(display, *out_retire_fence);
+  HandlePendingPowerMode(display, *out_retire_fence);
+  HandlePendingHotplug(display, *out_retire_fence);
   HandlePendingRefresh();
   cwb_.PresentDisplayDone(display);
   display_ready_.set(UINT32(display));
@@ -707,7 +711,7 @@
     int32_t err = HandlePluggableDisplays(false);
     if (err) {
       DLOGW("All displays could not be created. Error %d '%s'. Hotplug handling %s.", err,
-            strerror(abs(err)), hotplug_pending_event_ == kHotPlugEvent ? "deferred" :
+            strerror(abs(err)), pending_hotplug_event_ == kHotPlugEvent ? "deferred" :
             "dropped");
     }
     client_connected_ = true;
@@ -868,7 +872,7 @@
     return HWC2_ERROR_BAD_PARAMETER;
   }
 
-  if (power_on_pending_[display]) {
+  if (pending_power_mode_[display]) {
     DLOGW("Set power mode is not allowed during secure display session");
     return HWC2_ERROR_UNSUPPORTED;
   }
@@ -895,7 +899,7 @@
       return INT32(error);
     }
   } else {
-    SCOPE_LOCK(locker_[display]);
+    Locker::ScopeLock lock_disp(locker_[display]);
     // Update hwc state for now. Actual poweron will handled through DisplayConfig.
     hwc_display_[display]->UpdatePowerMode(mode);
   }
@@ -959,11 +963,13 @@
     return HWC2_ERROR_BAD_DISPLAY;
   }
 
+  hwc2_display_t target_display = display;
+
   {
     SCOPE_LOCK(power_state_[display]);
     if (power_state_transition_[display]) {
       // Route all interactions with client to dummy display.
-      display = map_hwc_display_.find(display)->second;
+      target_display = map_hwc_display_.find(display)->second;
     }
   }
   DTRACE_SCOPED();
@@ -971,18 +977,23 @@
   auto status = HWC2::Error::BadDisplay;
   HandleSecureSession();
   {
-    SEQUENCE_ENTRY_SCOPE_LOCK(locker_[display]);
-    if (power_on_pending_[display]) {
+    SEQUENCE_ENTRY_SCOPE_LOCK(locker_[target_display]);
+    if (pending_power_mode_[display]) {
       status = HWC2::Error::None;
-    } else if (hwc_display_[display]) {
-      hwc_display_[display]->SetFastPathComposition(false);
-      status = ValidateDisplayInternal(display, out_num_types, out_num_requests);
+    } else if (hwc_display_[target_display]) {
+      hwc_display_[target_display]->SetFastPathComposition(false);
+      status = ValidateDisplayInternal(target_display, out_num_types, out_num_requests);
     }
   }
 
   // Sequence locking currently begins on Validate, so cancel the sequence lock on failures
   if (status != HWC2::Error::None && status != HWC2::Error::HasChanges) {
-    SEQUENCE_CANCEL_SCOPE_LOCK(locker_[display]);
+    SEQUENCE_CANCEL_SCOPE_LOCK(locker_[target_display]);
+  }
+
+  if (display != target_display) {
+    // Validate done on a dummy display. Assume present is complete.
+    SEQUENCE_EXIT_SCOPE_LOCK(locker_[target_display]);
   }
 
   return INT32(status);
@@ -2125,13 +2136,13 @@
       // Defer hotplug handling.
       SCOPE_LOCK(pluggable_handler_lock_);
       DLOGI("Marking hotplug pending...");
-      hotplug_pending_event_ = kHotPlugEvent;
+      pending_hotplug_event_ = kHotPlugEvent;
     } else {
       // Handle hotplug.
       int32_t err = HandlePluggableDisplays(true);
       if (err) {
         DLOGW("Hotplug handling failed. Error %d '%s'. Hotplug handling %s.", err,
-              strerror(abs(err)), (hotplug_pending_event_ == kHotPlugEvent) ?
+              strerror(abs(err)), (pending_hotplug_event_ == kHotPlugEvent) ?
               "deferred" : "dropped");
       }
     }
@@ -2373,20 +2384,20 @@
       case -EAGAIN:
       case -ENODEV:
         // Errors like device removal or deferral for which we want to try another hotplug handling.
-        hotplug_pending_event_ = kHotPlugEvent;
+        pending_hotplug_event_ = kHotPlugEvent;
         status = 0;
         break;
       default:
         // Real errors we want to flag and stop hotplug handling.
-        hotplug_pending_event_ = kHotPlugNone;
+        pending_hotplug_event_ = kHotPlugNone;
         DLOGE("All displays could not be connected. Error %d '%s'.", status, strerror(abs(status)));
     }
-    DLOGI("Handling hotplug... %s", (kHotPlugNone ==hotplug_pending_event_) ?
+    DLOGI("Handling hotplug... %s", (kHotPlugNone == pending_hotplug_event_) ?
           "Stopped." : "Done. Hotplug events pending.");
     return status;
   }
 
-  hotplug_pending_event_ = kHotPlugNone;
+  pending_hotplug_event_ = kHotPlugNone;
 
   DLOGI("Handling hotplug... Done.");
   return 0;
@@ -2758,44 +2769,63 @@
 void HWCSession::HandleSecureSession() {
   std::bitset<kSecureMax> secure_sessions = 0;
   {
+    // TODO(user): Revisit if supporting secure display on non-primary.
     hwc2_display_t active_builtin_disp_id = GetActiveBuiltinDisplay();
     if (active_builtin_disp_id >= HWCCallbacks::kNumDisplays) {
       return;
     }
-    Locker::ScopeLock lock_a(locker_[active_builtin_disp_id]);
+    Locker::ScopeLock lock_pwr(power_state_[active_builtin_disp_id]);
+    if (power_state_transition_[active_builtin_disp_id]) {
+      // Route all interactions with client to dummy display.
+      active_builtin_disp_id = map_hwc_display_.find(active_builtin_disp_id)->second;
+    }
+    Locker::ScopeLock lock_d(locker_[active_builtin_disp_id]);
     hwc_display_[active_builtin_disp_id]->GetActiveSecureSession(&secure_sessions);
   }
 
+  if (secure_sessions.any()) {
+    secure_session_active_ = true;
+  } else if (!secure_session_active_) {
+    // No secure session active. No secure session transition to handle. Skip remaining steps.
+    return;
+  }
+
   // If it is called during primary prepare/commit, we need to pause any ongoing commit on
   // external/virtual display.
   for (hwc2_display_t display = HWC_DISPLAY_PRIMARY;
     display < HWCCallbacks::kNumDisplays; display++) {
     Locker::ScopeLock lock_d(locker_[display]);
     if (hwc_display_[display]) {
-      hwc_display_[display]->HandleSecureSession(secure_sessions, &power_on_pending_[display]);
+      hwc_display_[display]->HandleSecureSession(secure_sessions, &pending_power_mode_[display]);
     }
   }
 }
 
-void HWCSession::HandlePowerOnPending(hwc2_display_t disp_id, int retire_fence) {
+void HWCSession::HandlePendingPowerMode(hwc2_display_t disp_id, int retire_fence) {
+  if (!secure_session_active_) {
+    // No secure session active. Skip remaining steps.
+    return;
+  }
+
   hwc2_display_t active_builtin_disp_id = GetActiveBuiltinDisplay();
   if (disp_id != active_builtin_disp_id) {
     return;
   }
 
-  Locker::ScopeLock lock_a(locker_[active_builtin_disp_id]);
-  bool power_on_pending = false;
-  for (hwc2_display_t display = HWC_DISPLAY_PRIMARY;
+
+  Locker::ScopeLock lock_d(locker_[active_builtin_disp_id]);
+  bool pending_power_mode = false;
+  for (hwc2_display_t display = HWC_DISPLAY_PRIMARY + 1;
     display < HWCCallbacks::kNumDisplays; display++) {
     if (display != active_builtin_disp_id) {
       Locker::ScopeLock lock_d(locker_[display]);
-      if (power_on_pending_[display]) {
-        power_on_pending = true;
+      if (pending_power_mode_[display]) {
+        pending_power_mode = true;
         break;
       }
     }
   }
-  if (power_on_pending) {
+  if (pending_power_mode) {
     // retire fence is set only after successful primary commit, So check for retire fence to know
     // non secure commit went through to notify driver to change the CRTC mode to non secure.
     // Otherwise any commit to non-primary display would fail.
@@ -2810,31 +2840,36 @@
     return;
   }
 
-  for (hwc2_display_t display = HWC_DISPLAY_PRIMARY;
+  for (hwc2_display_t display = HWC_DISPLAY_PRIMARY + 1;
     display < HWCCallbacks::kNumDisplays; display++) {
     if (display != active_builtin_disp_id) {
       Locker::ScopeLock lock_d(locker_[display]);
-      if (power_on_pending_[display] && hwc_display_[display]) {
-        HWC2::Error status =
-          hwc_display_[display]->SetPowerMode(HWC2::PowerMode::On, false /* teardown */);
-        if (status == HWC2::Error::None) {
-          power_on_pending_[display] = false;
+      if (pending_power_mode_[display] && hwc_display_[display]) {
+        HWC2::Error error =
+          hwc_display_[display]->SetPowerMode(hwc_display_[display]->GetPendingPowerMode(), false);
+        if (HWC2::Error::None == error) {
+          pending_power_mode_[display] = false;
+          hwc_display_[display]->ClearPendingPowerMode();
+          pending_refresh_.set(UINT32(HWC_DISPLAY_PRIMARY));
+        } else {
+          DLOGE("SetDisplayStatus error = %d (%s)", error, to_string(error).c_str());
         }
       }
     }
   }
+  secure_session_active_ = false;
 }
 
-void HWCSession::HandleHotplugPending(hwc2_display_t disp_id, int retire_fence) {
+void HWCSession::HandlePendingHotplug(hwc2_display_t disp_id, int retire_fence) {
   hwc2_display_t active_builtin_disp_id = GetActiveBuiltinDisplay();
   if (disp_id != active_builtin_disp_id ||
-      (kHotPlugNone == hotplug_pending_event_ && !destroy_virtual_disp_pending_)) {
+      (kHotPlugNone == pending_hotplug_event_ && !destroy_virtual_disp_pending_)) {
     return;
   }
 
   std :: bitset < kSecureMax > secure_sessions = 0;
   if (active_builtin_disp_id < HWCCallbacks::kNumDisplays) {
-    Locker::ScopeLock lock_a(locker_[active_builtin_disp_id]);
+    Locker::ScopeLock lock_d(locker_[active_builtin_disp_id]);
     hwc_display_[active_builtin_disp_id]->GetActiveSecureSession(&secure_sessions);
   }
 
@@ -2842,7 +2877,7 @@
     return;
   }
 
-  if (destroy_virtual_disp_pending_ || kHotPlugEvent == hotplug_pending_event_) {
+  if (destroy_virtual_disp_pending_ || kHotPlugEvent == pending_hotplug_event_) {
     if (retire_fence >= 0) {
       int error = sync_wait(retire_fence, 1000);
       if (error < 0) {
@@ -2858,7 +2893,7 @@
     }
     // Handle connect/disconnect hotplugs if secure session is not present.
     hwc2_display_t virtual_display_idx = (hwc2_display_t)GetDisplayIndex(qdutils::DISPLAY_VIRTUAL);
-    if (!hwc_display_[virtual_display_idx] && kHotPlugEvent == hotplug_pending_event_) {
+    if (!hwc_display_[virtual_display_idx] && kHotPlugEvent == pending_hotplug_event_) {
       // Handle deferred hotplug event.
       int32_t err = pluggable_handler_lock_.TryLock();
       if (!err) {
@@ -3055,21 +3090,27 @@
 }
 
 hwc2_display_t HWCSession::GetActiveBuiltinDisplay() {
-  hwc2_display_t disp_id = HWCCallbacks::kNumDisplays;
+  hwc2_display_t active_display = HWCCallbacks::kNumDisplays;
   // Get first active display among primary and built-in displays.
   std::vector<DisplayMapInfo> map_info = {map_info_primary_};
   std::copy(map_info_builtin_.begin(), map_info_builtin_.end(), std::back_inserter(map_info));
 
   for (auto &info : map_info) {
-    SCOPE_LOCK(locker_[info.client_id]);
-    auto &hwc_display = hwc_display_[info.client_id];
+    hwc2_display_t target_display = info.client_id;
+    SCOPE_LOCK(power_state_[target_display]);
+    if (power_state_transition_[target_display]) {
+      // Route all interactions with client to dummy display.
+      target_display = map_hwc_display_.find(target_display)->second;
+    }
+    Locker::ScopeLock lock_d(locker_[target_display]);
+    auto &hwc_display = hwc_display_[target_display];
     if (hwc_display && hwc_display->GetCurrentPowerMode() != HWC2::PowerMode::Off) {
-      disp_id = info.client_id;
+      active_display = info.client_id;
       break;
     }
   }
 
-  return disp_id;
+  return active_display;
 }
 
 int32_t HWCSession::SetDisplayBrightnessScale(const android::Parcel *input_parcel) {
diff --git a/composer/hwc_session.h b/composer/hwc_session.h
index de8d4cd..e5199d9 100644
--- a/composer/hwc_session.h
+++ b/composer/hwc_session.h
@@ -434,8 +434,8 @@
                                       uint32_t *out_num_requests);
   HWC2::Error PresentDisplayInternal(hwc2_display_t display, int32_t *out_retire_fence);
   void HandleSecureSession();
-  void HandlePowerOnPending(hwc2_display_t display, int retire_fence);
-  void HandleHotplugPending(hwc2_display_t disp_id, int retire_fence);
+  void HandlePendingPowerMode(hwc2_display_t display, int retire_fence);
+  void HandlePendingHotplug(hwc2_display_t disp_id, int retire_fence);
   bool IsPluggableDisplayConnected();
   hwc2_display_t GetActiveBuiltinDisplay();
   void HandlePendingRefresh();
@@ -467,9 +467,9 @@
   std::mutex mutex_lum_;
   int hpd_bpp_ = 0;
   int hpd_pattern_ = 0;
-  static bool power_on_pending_[HWCCallbacks::kNumDisplays];
+  static bool pending_power_mode_[HWCCallbacks::kNumDisplays];
   static int null_display_mode_;
-  HotPlugEvent hotplug_pending_event_ = kHotPlugNone;
+  HotPlugEvent pending_hotplug_event_ = kHotPlugNone;
   Locker pluggable_handler_lock_;
   bool destroy_virtual_disp_pending_ = false;
   uint32_t idle_pc_ref_cnt_ = 0;
@@ -482,6 +482,7 @@
   bool async_powermode_ = false;
   bool power_state_transition_[HWCCallbacks::kNumDisplays] = {};
   std::bitset<HWCCallbacks::kNumDisplays> display_ready_;
+  bool secure_session_active_ = false;
 };
 }  // namespace sdm
 
diff --git a/composer/hwc_session_services.cpp b/composer/hwc_session_services.cpp
index 898316e..afd60db 100644
--- a/composer/hwc_session_services.cpp
+++ b/composer/hwc_session_services.cpp
@@ -659,6 +659,7 @@
     hwc_display_[disp_id]->GetLayerStack(&stack);
     // Update the same stack onto dummy display.
     hwc_display_[dummy_disp_id]->SetLayerStack(&stack);
+    hwc_display_[dummy_disp_id]->UpdatePowerMode(hwc_display_[disp_id]->GetCurrentPowerMode());
   }
 
   {