Revert "Tie vr flinger to persistent vr mode"

This reverts commit f43d13e4e35ae7d3cdafc4b97c819669d42cef78.

Change-Id: Ib67db8e51b7ea2dbbe6faccce36962bf5b44a6e2
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 9a3edef..dcdd994 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -248,6 +248,29 @@
   return 0;
 }
 
+int DisplayClient::EnterVrMode() {
+  auto status = InvokeRemoteMethod<DisplayRPC::EnterVrMode>();
+  if (!status) {
+    ALOGE(
+        "DisplayClient::EnterVrMode: Failed to set display service to Vr mode");
+    return -status.error();
+  }
+
+  return 0;
+}
+
+int DisplayClient::ExitVrMode() {
+  auto status = InvokeRemoteMethod<DisplayRPC::ExitVrMode>();
+  if (!status) {
+    ALOGE(
+        "DisplayClient::ExitVrMode: Failed to revert display service from Vr "
+        "mode");
+    return -status.error();
+  }
+
+  return 0;
+}
+
 std::unique_ptr<DisplaySurfaceClient> DisplayClient::CreateDisplaySurface(
     int width, int height, int format, int usage, int flags) {
   return DisplaySurfaceClient::Create(width, height, format, usage, flags);
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index 3a6e3b6..e1471c3 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -105,6 +105,9 @@
   // Pull the latest eds pose data from the display service renderer
   int GetLastFrameEdsTransform(LateLatchOutput* ll_out);
 
+  int EnterVrMode();
+  int ExitVrMode();
+
   std::unique_ptr<DisplaySurfaceClient> CreateDisplaySurface(
       int width, int height, int format, int usage, int flags);
 
diff --git a/libs/vr/libdisplay/include/private/dvr/display_rpc.h b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
index 2d1bbd8..465fbae 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
@@ -217,6 +217,8 @@
     kOpGetMetadataBuffer,
     kOpCreateVideoMeshSurface,
     kOpVideoMeshSurfaceCreateProducerQueue,
+    kOpEnterVrMode,
+    kOpExitVrMode,
     kOpSetViewerParams
   };
 
@@ -243,6 +245,8 @@
   PDX_REMOTE_METHOD(VideoMeshSurfaceCreateProducerQueue,
                     kOpVideoMeshSurfaceCreateProducerQueue,
                     LocalChannelHandle(Void));
+  PDX_REMOTE_METHOD(EnterVrMode, kOpEnterVrMode, int(Void));
+  PDX_REMOTE_METHOD(ExitVrMode, kOpExitVrMode, int(Void));
   PDX_REMOTE_METHOD(SetViewerParams, kOpSetViewerParams,
                     void(const ViewerParams& viewer_params));
 };
diff --git a/libs/vr/libvr_manager/vr_manager.cpp b/libs/vr/libvr_manager/vr_manager.cpp
index 5cfc22e..d24cbb5 100644
--- a/libs/vr/libvr_manager/vr_manager.cpp
+++ b/libs/vr/libvr_manager/vr_manager.cpp
@@ -53,40 +53,6 @@
   return BBinder::onTransact(code, data, reply, flags);
 }
 
-// Must be kept in sync with interface defined in
-// IPersistentVrStateCallbacks.aidl.
-
-class BpPersistentVrStateCallbacks
-    : public BpInterface<IPersistentVrStateCallbacks> {
- public:
-  explicit BpPersistentVrStateCallbacks(const sp<IBinder>& impl)
-      : BpInterface<IPersistentVrStateCallbacks>(impl) {}
-
-  void onPersistentVrStateChanged(bool enabled) {
-    Parcel data, reply;
-    data.writeInterfaceToken(
-        IPersistentVrStateCallbacks::getInterfaceDescriptor());
-    data.writeBool(enabled);
-    remote()->transact(ON_PERSISTENT_VR_STATE_CHANGED,
-                       data, &reply, IBinder::FLAG_ONEWAY);
-  }
-};
-
-IMPLEMENT_META_INTERFACE(PersistentVrStateCallbacks,
-                         "android.service.vr.IPersistentVrStateCallbacks");
-
-status_t BnPersistentVrStateCallbacks::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
-  switch(code) {
-    case ON_PERSISTENT_VR_STATE_CHANGED: {
-      CHECK_INTERFACE(IPersistentVrStateCallbacks, data, reply);
-      onPersistentVrStateChanged(data.readBool());
-      return OK;
-    }
-  }
-  return BBinder::onTransact(code, data, reply, flags);
-}
-
 // Must be kept in sync with interface defined in IVrManager.aidl.
 
 class BpVrManager : public BpInterface<IVrManager> {
@@ -108,22 +74,6 @@
     remote()->transact(UNREGISTER_LISTENER, data, NULL);
   }
 
-  void registerPersistentVrStateListener(
-      const sp<IPersistentVrStateCallbacks>& cb) override {
-    Parcel data;
-    data.writeInterfaceToken(IVrManager::getInterfaceDescriptor());
-    data.writeStrongBinder(IInterface::asBinder(cb));
-    remote()->transact(REGISTER_PERSISTENT_VR_STATE_LISTENER, data, NULL);
-  }
-
-  void unregisterPersistentVrStateListener(
-      const sp<IPersistentVrStateCallbacks>& cb) override {
-    Parcel data;
-    data.writeInterfaceToken(IVrManager::getInterfaceDescriptor());
-    data.writeStrongBinder(IInterface::asBinder(cb));
-    remote()->transact(UNREGISTER_PERSISTENT_VR_STATE_LISTENER, data, NULL);
-  }
-
   bool getVrModeState() override {
     Parcel data, reply;
     data.writeInterfaceToken(IVrManager::getInterfaceDescriptor());
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index b5210c9..fdb84c5 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -21,8 +21,7 @@
 namespace android {
 namespace dvr {
 
-DisplayService::DisplayService()
-    : DisplayService(nullptr) {}
+DisplayService::DisplayService() : DisplayService(nullptr) {}
 
 DisplayService::DisplayService(Hwc2::Composer* hidl)
     : BASE("DisplayService", Endpoint::Create(DisplayRPC::kClientPath)),
@@ -75,6 +74,16 @@
           *this, &DisplayService::OnCreateSurface, message);
       return 0;
 
+    case DisplayRPC::EnterVrMode::Opcode:
+      DispatchRemoteMethod<DisplayRPC::EnterVrMode>(
+          *this, &DisplayService::OnEnterVrMode, message);
+      return 0;
+
+    case DisplayRPC::ExitVrMode::Opcode:
+      DispatchRemoteMethod<DisplayRPC::ExitVrMode>(
+          *this, &DisplayService::OnExitVrMode, message);
+      return 0;
+
     case DisplayRPC::SetViewerParams::Opcode:
       DispatchRemoteMethod<DisplayRPC::SetViewerParams>(
           *this, &DisplayService::OnSetViewerParams, message);
@@ -173,6 +182,16 @@
   return WrapBuffer(std::move(buffer));
 }
 
+int DisplayService::OnEnterVrMode(pdx::Message& /*message*/) {
+  hardware_composer_.Resume();
+  return 0;
+}
+
+int DisplayService::OnExitVrMode(pdx::Message& /*message*/) {
+  hardware_composer_.Suspend();
+  return 0;
+}
+
 void DisplayService::OnSetViewerParams(pdx::Message& message,
                                        const ViewerParams& view_params) {
   Compositor* compositor = hardware_composer_.GetCompositor();
@@ -271,7 +290,7 @@
   return visible_surfaces;
 }
 
-void DisplayService::UpdateActiveDisplaySurfaces() {
+int DisplayService::UpdateActiveDisplaySurfaces() {
   auto visible_surfaces = GetVisibleDisplaySurfaces();
 
   // Sort the surfaces based on manager z order first, then client z order.
@@ -302,8 +321,7 @@
     if (surface->client_blur_behind())
       blur_requested = true;
   }
-
-  hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
+  return hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
 }
 
 void DisplayService::OnHardwareComposerRefresh() {
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index c93488a..9d116c1 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -36,7 +36,7 @@
 
   // Updates the list of actively displayed surfaces. This must be called after
   // any change to client/manager attributes that affect visibility or z order.
-  void UpdateActiveDisplaySurfaces();
+  int UpdateActiveDisplaySurfaces();
 
   template <class A>
   void ForEachDisplaySurface(A action) const {
@@ -60,8 +60,13 @@
     return hardware_composer_.display_metrics();
   }
 
-  void GrantDisplayOwnership() { hardware_composer_.Enable(); }
-  void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
+  void SetActive(bool activated) {
+    if (activated) {
+      hardware_composer_.Resume();
+    } else {
+      hardware_composer_.Suspend();
+    }
+  }
 
   void OnHardwareComposerRefresh();
 
@@ -80,6 +85,8 @@
 
   DisplayRPC::ByteBuffer OnGetEdsCapture(pdx::Message& message);
 
+  int OnEnterVrMode(pdx::Message& message);
+  int OnExitVrMode(pdx::Message& message);
   void OnSetViewerParams(pdx::Message& message, const ViewerParams& view_params);
 
   // Called by DisplaySurface to signal that a surface property has changed and
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index da45859..53c2ac2 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -103,13 +103,12 @@
     : initialized_(false),
       hwc2_hidl_(hwc2_hidl),
       display_transform_(HWC_TRANSFORM_NONE),
-      active_surfaces_updated_(false),
+      display_surfaces_updated_(false),
+      hardware_layers_need_update_(false),
       active_layer_count_(0),
       gpu_layer_(nullptr),
-      post_thread_enabled_(false),
-      post_thread_running_(false),
-      post_thread_quit_requested_(false),
-      post_thread_interrupt_event_fd_(-1),
+      post_thread_state_(PostThreadState::kPaused),
+      terminate_post_thread_event_fd_(-1),
       backlight_brightness_fd_(-1),
       primary_display_vsync_event_fd_(-1),
       primary_display_wait_pp_fd_(-1),
@@ -125,12 +124,7 @@
 }
 
 HardwareComposer::~HardwareComposer(void) {
-  std::unique_lock<std::mutex> lock(post_thread_mutex_);
-  if (post_thread_.joinable()) {
-    post_thread_quit_requested_ = true;
-    post_thread_cond_var_.notify_all();
-    post_thread_.join();
-  }
+  Suspend();
 }
 
 bool HardwareComposer::Initialize() {
@@ -173,56 +167,24 @@
   display_transform_ = HWC_TRANSFORM_NONE;
   display_metrics_ = native_display_metrics_;
 
-  post_thread_interrupt_event_fd_.Reset(
-      eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
-  LOG_ALWAYS_FATAL_IF(
-      !post_thread_interrupt_event_fd_,
-      "HardwareComposer: Failed to create interrupt event fd : %s",
-      strerror(errno));
-
-  post_thread_ = std::thread(&HardwareComposer::PostThread, this);
-
   initialized_ = true;
 
   return initialized_;
 }
 
-void HardwareComposer::Enable() {
-  std::lock_guard<std::mutex> lock(post_thread_mutex_);
-  post_thread_enabled_ = true;
-  post_thread_cond_var_.notify_all();
-}
-
-void HardwareComposer::Disable() {
-  std::unique_lock<std::mutex> lock(post_thread_mutex_);
-  post_thread_enabled_ = false;
-  if (post_thread_running_) {
-    // Write to the interrupt fd to get fast interrupt of the post thread
-    int error = eventfd_write(post_thread_interrupt_event_fd_.Get(), 1);
-    ALOGW_IF(error,
-             "HardwareComposer::Disable: could not write post "
-             "thread interrupt event fd : %s",
-             strerror(errno));
-
-    post_thread_cond_var_.wait(lock, [this] { return !post_thread_running_; });
-
-    // Read the interrupt fd to clear its state
-    uint64_t interrupt_count= 0;
-    error = eventfd_read(post_thread_interrupt_event_fd_.Get(),
-                         &interrupt_count);
-    ALOGW_IF(error,
-             "HardwareComposer::Disable: could not read post "
-             "thread interrupt event fd : %s",
-             strerror(errno));
+bool HardwareComposer::Resume() {
+  std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
+  if (post_thread_state_ == PostThreadState::kRunning) {
+    return false;
   }
-}
 
-bool HardwareComposer::PostThreadHasWork() {
-  return !display_surfaces_.empty() ||
-      (active_surfaces_updated_ && !active_surfaces_.empty());
-}
+  std::lock_guard<std::mutex> layer_lock(layer_mutex_);
 
-void HardwareComposer::OnPostThreadResumed() {
+  int32_t ret = HWC2_ERROR_NONE;
+
+  // Always turn off vsync when we start.
+  EnableVsync(false);
+
   constexpr int format = HAL_PIXEL_FORMAT_RGBA_8888;
   constexpr int usage =
       GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER;
@@ -236,33 +198,97 @@
     layer->Initialize(hwc2_hidl_.get(), &native_display_metrics_);
   }
 
+#if ENABLE_BACKLIGHT_BRIGHTNESS
+  // TODO(hendrikw): This isn't required at the moment. It's possible that there
+  //                 is another method to access this when needed.
+  // Open the backlight brightness control sysfs node.
+  backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR);
+  ALOGW_IF(!backlight_brightness_fd_,
+           "HardwareComposer: Failed to open backlight brightness control: %s",
+           strerror(errno));
+#endif // ENABLE_BACKLIGHT_BRIGHTNESS
+
+  // Open the vsync event node for the primary display.
+  // TODO(eieio): Move this into a platform-specific class.
+  primary_display_vsync_event_fd_ =
+      LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY);
+  ALOGE_IF(!primary_display_vsync_event_fd_,
+           "HardwareComposer: Failed to open vsync event node for primary "
+           "display: %s",
+           strerror(errno));
+
+  // Open the wait pingpong status node for the primary display.
+  // TODO(eieio): Move this into a platform-specific class.
+  primary_display_wait_pp_fd_ =
+      LocalHandle(kPrimaryDisplayWaitPPEventFile, O_RDONLY);
+  ALOGE_IF(
+      !primary_display_wait_pp_fd_,
+      "HardwareComposer: Failed to open wait_pp node for primary display: %s",
+      strerror(errno));
+
+  // Create a timerfd based on CLOCK_MONOTINIC.
+  vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
+  LOG_ALWAYS_FATAL_IF(
+      !vsync_sleep_timer_fd_,
+      "HardwareComposer: Failed to create vsync sleep timerfd: %s",
+      strerror(errno));
+
   // Connect to pose service.
   pose_client_ = dvrPoseCreate();
   ALOGE_IF(!pose_client_, "HardwareComposer: Failed to create pose client");
 
-  EnableVsync(true);
+  terminate_post_thread_event_fd_.Reset(
+      eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+  LOG_ALWAYS_FATAL_IF(
+      !terminate_post_thread_event_fd_,
+      "HardwareComposer: Failed to create terminate PostThread event fd : %s",
+      strerror(errno));
 
-  // TODO(skiazyk): We need to do something about accessing this directly,
-  // supposedly there is a backlight service on the way.
-  // TODO(steventhomas): When we change the backlight setting, will surface
-  // flinger (or something else) set it back to its original value once we give
-  // control of the display back to surface flinger?
-  SetBacklightBrightness(255);
+  post_thread_state_ = PostThreadState::kRunning;
+  post_thread_state_cond_var_.notify_all();
 
-  // Initialize the GPU compositor.
-  LOG_ALWAYS_FATAL_IF(!compositor_.Initialize(GetHmdDisplayMetrics()),
-                      "Failed to initialize the compositor");
+  // If get_id() is the default thread::id object, it has not been created yet
+  if (post_thread_.get_id() == std::thread::id()) {
+    post_thread_ = std::thread(&HardwareComposer::PostThread, this);
+  } else {
+    UpdateDisplayState();
+  }
 
-  // Trigger target-specific performance mode change.
-  property_set(kDvrPerformanceProperty, "performance");
+  return true;
 }
 
-void HardwareComposer::OnPostThreadPaused() {
+bool HardwareComposer::Suspend() {
+  std::unique_lock<std::mutex> post_thread_lock(post_thread_state_mutex_);
+  if (post_thread_state_ == PostThreadState::kPaused) {
+    return false;
+  }
+
+  post_thread_state_ = PostThreadState::kPauseRequested;
+
+  int error = eventfd_write(terminate_post_thread_event_fd_.Get(), 1);
+  ALOGE_IF(error,
+           "HardwareComposer::Suspend: could not write post "
+           "thread termination event fd : %d",
+           error);
+
+  post_thread_state_cond_var_.wait(
+      post_thread_lock,
+      [this] { return post_thread_state_ == PostThreadState::kPaused; });
+  terminate_post_thread_event_fd_.Close();
+
+  // Wait for any pending layer operations to finish
+  std::lock_guard<std::mutex> layer_lock(layer_mutex_);
+
+  EnableVsync(false);
+
+  backlight_brightness_fd_.Close();
+  primary_display_vsync_event_fd_.Close();
+  primary_display_wait_pp_fd_.Close();
+  vsync_sleep_timer_fd_.Close();
   retire_fence_fds_.clear();
   gpu_layer_ = nullptr;
 
-  // We have to destroy the layers to fully clear hwc device state before
-  // handing off back to surface flinger
+  // We have to destroy the layers before we close the hwc device
   for (size_t i = 0; i < kMaxHardwareLayers; ++i) {
     layers_[i]->Reset();
   }
@@ -271,26 +297,12 @@
 
   framebuffer_target_.reset();
 
-  display_surfaces_.clear();
-  compositor_surfaces_.clear();
+  //hwc2_hidl_.reset();
 
-  // Since we're clearing display_surfaces_ we'll need an update.
-  active_surfaces_updated_ = true;
-
-  if (pose_client_) {
+  if (pose_client_)
     dvrPoseDestroy(pose_client_);
-    pose_client_ = nullptr;
-  }
 
-  EnableVsync(false);
-
-  frame_time_history_.ResetWithSeed(GuessFrameTime(0));
-  frame_time_backlog_.clear();
-
-  compositor_.Shutdown();
-
-  // Trigger target-specific performance mode change.
-  property_set(kDvrPerformanceProperty, "idle");
+  return true;
 }
 
 DisplayMetrics HardwareComposer::GetHmdDisplayMetrics() const {
@@ -507,48 +519,82 @@
   }
 }
 
-void HardwareComposer::SetDisplaySurfaces(
-    std::vector<std::shared_ptr<DisplaySurface>> surfaces) {
-  ALOGI("HardwareComposer::SetDisplaySurfaces: surface count=%zd",
-        surfaces.size());
-  std::unique_lock<std::mutex> lock(post_thread_mutex_);
-  active_surfaces_ = std::move(surfaces);
-  active_surfaces_updated_ = true;
-  if (post_thread_enabled_)
-    post_thread_cond_var_.notify_all();
+// TODO(skiazyk): This is a work-around for the fact that we currently do not
+// handle the case when new surfaces are introduced when displayd is not
+// in an active state. A proper-solution will require re-structuring
+// displayd a little, but hopefully this is sufficient for now.
+// For example, could this be handled in |UpdateLayerSettings| instead?
+void HardwareComposer::UpdateDisplayState() {
+  const bool has_display_surfaces = display_surfaces_.size() > 0;
+
+  if (has_display_surfaces) {
+    EnableVsync(true);
+  }
+
+  // TODO(skiazyk): We need to do something about accessing this directly,
+  // supposedly there is a backlight service on the way.
+  SetBacklightBrightness(255);
+
+  // Trigger target-specific performance mode change.
+  property_set(kDvrPerformanceProperty, has_display_surfaces ? "performance" : "idle");
 }
 
-int HardwareComposer::PostThreadPollInterruptible(int event_fd) {
-  pollfd pfd[2] = {
-      {
-          .fd = event_fd, .events = POLLPRI | POLLIN, .revents = 0,
-      },
-      {
-          .fd = post_thread_interrupt_event_fd_.Get(),
-          .events = POLLPRI | POLLIN,
-          .revents = 0,
-      },
-  };
-  int ret, error;
-  do {
-    ret = poll(pfd, 2, -1);
-    error = errno;
-    ALOGW_IF(ret < 0,
-             "HardwareComposer::PostThreadPollInterruptible: Error during "
-             "poll(): %s (%d)",
-             strerror(error), error);
-  } while (ret < 0 && error == EINTR);
+int HardwareComposer::SetDisplaySurfaces(
+    std::vector<std::shared_ptr<DisplaySurface>> surfaces) {
+  // The double lock is necessary because we access both the display surfaces
+  // and post_thread_state_.
+  std::lock_guard<std::mutex> post_thread_state_lock(post_thread_state_mutex_);
+  std::lock_guard<std::mutex> layer_lock(layer_mutex_);
 
-  if (ret < 0) {
-    return -error;
-  } else if (pfd[0].revents != 0) {
-    return 0;
-  } else if (pfd[1].revents != 0) {
-    ALOGI("VrHwcPost thread interrupted");
-    return kPostThreadInterrupted;
-  } else {
-    return 0;
+  ALOGI("HardwareComposer::SetDisplaySurfaces: surface count=%zd",
+        surfaces.size());
+
+  // Figure out whether we need to update hardware layers. If this surface
+  // change does not add or remove hardware layers we can avoid display hiccups
+  // by gracefully updating only the GPU compositor layers.
+  // hardware_layers_need_update_ is reset to false by the Post thread.
+  int old_gpu_layer_count = 0;
+  int new_gpu_layer_count = 0;
+  // Look for new hardware layers and count new GPU layers.
+  for (const auto& surface : surfaces) {
+    if (!(surface->flags() &
+          DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION))
+      ++new_gpu_layer_count;
+    else if (std::find(display_surfaces_.begin(), display_surfaces_.end(),
+                       surface) == display_surfaces_.end())
+      // This is a new hardware layer, we need to update.
+      hardware_layers_need_update_ = true;
   }
+  // Look for deleted hardware layers or compositor layers.
+  for (const auto& surface : display_surfaces_) {
+    if (!(surface->flags() &
+          DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION))
+      ++old_gpu_layer_count;
+    else if (std::find(surfaces.begin(), surfaces.end(), surface) ==
+             surfaces.end())
+      // This is a deleted hardware layer, we need to update.
+      hardware_layers_need_update_ = true;
+  }
+  // Check for compositor hardware layer transition.
+  if ((!old_gpu_layer_count && new_gpu_layer_count) ||
+      (old_gpu_layer_count && !new_gpu_layer_count))
+    hardware_layers_need_update_ = true;
+
+  display_surfaces_ = std::move(surfaces);
+  display_surfaces_updated_ = true;
+
+  // Set the chosen layer order for all surfaces.
+  for (size_t i = 0; i < display_surfaces_.size(); ++i) {
+    display_surfaces_[i]->SetLayerOrder(static_cast<int>(i));
+  }
+
+  // TODO(skiazyk): fix this so that it is handled seamlessly with dormant/non-
+  // dormant state.
+  if (post_thread_state_ == PostThreadState::kRunning) {
+    UpdateDisplayState();
+  }
+
+  return 0;
 }
 
 // Reads the value of the display driver wait_pingpong state. Returns 0 or 1
@@ -644,8 +690,35 @@
 // Blocks until the next vsync event is signaled by the display driver.
 // TODO(eieio): This is pretty driver specific, this should be moved to a
 // separate class eventually.
-int HardwareComposer::BlockUntilVSync() {
-  return PostThreadPollInterruptible(primary_display_vsync_event_fd_.Get());
+int HardwareComposer::BlockUntilVSync(/*out*/ bool* suspend_requested) {
+  *suspend_requested = false;
+  const int event_fd = primary_display_vsync_event_fd_.Get();
+  pollfd pfd[2] = {
+      {
+          .fd = event_fd, .events = POLLPRI, .revents = 0,
+      },
+      // This extra event fd is to ensure that we can break out of this loop to
+      // pause the thread even when vsync is disabled, and thus no events on the
+      // vsync fd are being generated.
+      {
+          .fd = terminate_post_thread_event_fd_.Get(),
+          .events = POLLPRI | POLLIN,
+          .revents = 0,
+      },
+  };
+  int ret, error;
+  do {
+    ret = poll(pfd, 2, -1);
+    error = errno;
+    ALOGW_IF(ret < 0,
+             "HardwareComposer::BlockUntilVSync: Error while waiting for vsync "
+             "event: %s (%d)",
+             strerror(error), error);
+  } while (ret < 0 && error == EINTR);
+
+  if (ret >= 0 && pfd[1].revents != 0)
+    *suspend_requested = true;
+  return ret < 0 ? -error : 0;
 }
 
 // Waits for the next vsync and returns the timestamp of the vsync event. If
@@ -667,8 +740,9 @@
 
     if (error == -EAGAIN) {
       // Vsync was turned off, wait for the next vsync event.
-      error = BlockUntilVSync();
-      if (error < 0 || error == kPostThreadInterrupted)
+      bool suspend_requested = false;
+      error = BlockUntilVSync(&suspend_requested);
+      if (error < 0 || suspend_requested)
         return error;
 
       // Try again to get the timestamp for this new vsync interval.
@@ -691,14 +765,13 @@
 
     if (distance_to_vsync_est > threshold_ns) {
       // Wait for vsync event notification.
-      error = BlockUntilVSync();
-      if (error < 0 || error == kPostThreadInterrupted)
+      bool suspend_requested = false;
+      error = BlockUntilVSync(&suspend_requested);
+      if (error < 0 || suspend_requested)
         return error;
     } else {
-      // Sleep for a short time (1 millisecond) before retrying.
-      error = SleepUntil(GetSystemClockNs() + 1000000);
-      if (error < 0 || error == kPostThreadInterrupted)
-        return error;
+      // Sleep for a short time before retrying.
+      std::this_thread::sleep_for(std::chrono::milliseconds(1));
     }
   }
 }
@@ -718,12 +791,21 @@
     return -error;
   }
 
-  return PostThreadPollInterruptible(timer_fd);
+  // Wait for the timer by reading the expiration count.
+  uint64_t expiration_count;
+  ret = read(timer_fd, &expiration_count, sizeof(expiration_count));
+  if (ret < 0) {
+    ALOGE("HardwareComposer::SleepUntil: Failed to wait for timerfd: %s",
+          strerror(error));
+    return -error;
+  }
+
+  return 0;
 }
 
 void HardwareComposer::PostThread() {
   // NOLINTNEXTLINE(runtime/int)
-  prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrHwcPost"), 0, 0, 0);
+  prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("PostThread"), 0, 0, 0);
 
   // Set the scheduler to SCHED_FIFO with high priority.
   int error = dvrSetSchedulerClass(0, "graphics:high");
@@ -737,40 +819,12 @@
       "HardwareComposer::PostThread: Failed to set cpu partition: %s",
       strerror(-error));
 
-#if ENABLE_BACKLIGHT_BRIGHTNESS
-  // TODO(hendrikw): This isn't required at the moment. It's possible that there
-  //                 is another method to access this when needed.
-  // Open the backlight brightness control sysfs node.
-  backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR);
-  ALOGW_IF(!backlight_brightness_fd_,
-           "HardwareComposer: Failed to open backlight brightness control: %s",
-           strerror(errno));
-#endif // ENABLE_BACKLIGHT_BRIGHTNESS
+  // Force the layers to be setup at least once.
+  display_surfaces_updated_ = true;
 
-  // Open the vsync event node for the primary display.
-  // TODO(eieio): Move this into a platform-specific class.
-  primary_display_vsync_event_fd_ =
-      LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY);
-  ALOGE_IF(!primary_display_vsync_event_fd_,
-           "HardwareComposer: Failed to open vsync event node for primary "
-           "display: %s",
-           strerror(errno));
-
-  // Open the wait pingpong status node for the primary display.
-  // TODO(eieio): Move this into a platform-specific class.
-  primary_display_wait_pp_fd_ =
-      LocalHandle(kPrimaryDisplayWaitPPEventFile, O_RDONLY);
-  ALOGW_IF(
-      !primary_display_wait_pp_fd_,
-      "HardwareComposer: Failed to open wait_pp node for primary display: %s",
-      strerror(errno));
-
-  // Create a timerfd based on CLOCK_MONOTINIC.
-  vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
-  LOG_ALWAYS_FATAL_IF(
-      !vsync_sleep_timer_fd_,
-      "HardwareComposer: Failed to create vsync sleep timerfd: %s",
-      strerror(errno));
+  // Initialize the GPU compositor.
+  LOG_ALWAYS_FATAL_IF(!compositor_.Initialize(GetHmdDisplayMetrics()),
+                      "Failed to initialize the compositor");
 
   const int64_t ns_per_frame = display_metrics_.vsync_period_ns;
   const int64_t photon_offset_ns = GetPosePredictionTimeOffset(ns_per_frame);
@@ -784,48 +838,41 @@
   right_eye_photon_offset_ns =
       property_get_int64(kRightEyeOffsetProperty, right_eye_photon_offset_ns);
 
-  compositor_surfaces_.reserve(2);
+  // The list of surfaces the compositor should attempt to render. This is set
+  // at the start of each frame.
+  std::vector<std::shared_ptr<DisplaySurface>> compositor_surfaces;
+  compositor_surfaces.reserve(2);
 
+  // Our history of frame times. This is used to get a better estimate of how
+  // long the next frame will take, to set a schedule for EDS.
+  FrameTimeHistory frame_time_history;
+
+  // The backlog is used to allow us to start rendering the next frame before
+  // the previous frame has finished, and still get an accurate measurement of
+  // frame duration.
+  std::vector<FrameTimeMeasurementRecord> frame_time_backlog;
   constexpr int kFrameTimeBacklogMax = 2;
-  frame_time_backlog_.reserve(kFrameTimeBacklogMax);
+  frame_time_backlog.reserve(kFrameTimeBacklogMax);
 
   // Storage for retrieving fence info.
   FenceInfoBuffer fence_info_buffer;
 
-  bool was_running = false;
-
   while (1) {
     ATRACE_NAME("HardwareComposer::PostThread");
 
     {
-      std::unique_lock<std::mutex> lock(post_thread_mutex_);
-      while (!post_thread_enabled_ || post_thread_quit_requested_ ||
-             !PostThreadHasWork()) {
-        if (was_running) {
-          const char* pause_reason = "unknown";
-          if (!post_thread_enabled_)
-            pause_reason = "disabled";
-          else if (post_thread_quit_requested_)
-            pause_reason = "quit requested";
-          else if (!PostThreadHasWork())
-            pause_reason = "no work";
-          ALOGI("VrHwcPost thread paused. Reason: %s.", pause_reason);
-          OnPostThreadPaused();
-          was_running = false;
-        }
-        post_thread_running_ = false;
-        post_thread_cond_var_.notify_all();
-        if (post_thread_quit_requested_)
-          return;
-        post_thread_cond_var_.wait(lock);
+      std::unique_lock<std::mutex> post_thread_lock(post_thread_state_mutex_);
+      if (post_thread_state_ == PostThreadState::kPauseRequested) {
+        ALOGI("HardwareComposer::PostThread: Post thread pause requested.");
+        post_thread_state_ = PostThreadState::kPaused;
+        post_thread_state_cond_var_.notify_all();
+        post_thread_state_cond_var_.wait(
+            post_thread_lock,
+            [this] { return post_thread_state_ == PostThreadState::kRunning; });
+        // The layers will need to be updated since they were deleted previously
+        display_surfaces_updated_ = true;
+        hardware_layers_need_update_ = true;
       }
-      post_thread_running_ = true;
-    }
-
-    if (!was_running) {
-      ALOGI("VrHwcPost thread resumed");
-      OnPostThreadResumed();
-      was_running = true;
     }
 
     int64_t vsync_timestamp = 0;
@@ -840,13 +887,22 @@
           error < 0,
           "HardwareComposer::PostThread: Failed to wait for vsync event: %s",
           strerror(-error));
+
       // Don't bother processing this frame if a pause was requested
-      if (error == kPostThreadInterrupted)
+      std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
+      if (post_thread_state_ == PostThreadState::kPauseRequested) {
         continue;
+      }
     }
 
     ++vsync_count_;
 
+    static double last_print_time = -1;
+    double current_time = GetSystemClockSec();
+    if (last_print_time < 0 || current_time - last_print_time > 3) {
+      last_print_time = current_time;
+    }
+
     if (pose_client_) {
       // Signal the pose service with vsync info.
       // Display timestamp is in the middle of scanout.
@@ -855,24 +911,24 @@
                                 ns_per_frame, right_eye_photon_offset_ns);
     }
 
-    bool layer_config_changed = UpdateLayerConfig();
+    bool layer_config_changed = UpdateLayerConfig(&compositor_surfaces);
 
-    if (!was_running || layer_config_changed) {
-      frame_time_history_.ResetWithSeed(
-          GuessFrameTime(compositor_surfaces_.size()));
-      frame_time_backlog_.clear();
+    if (layer_config_changed) {
+      frame_time_history.ResetWithSeed(
+          GuessFrameTime(compositor_surfaces.size()));
+      frame_time_backlog.clear();
     } else {
-      UpdateFrameTimeHistory(&frame_time_backlog_, kFrameTimeBacklogMax,
-                             &fence_info_buffer, &frame_time_history_);
+      UpdateFrameTimeHistory(&frame_time_backlog, kFrameTimeBacklogMax,
+                             &fence_info_buffer, &frame_time_history);
     }
 
     // Get our current best estimate at how long the next frame will take to
     // render, based on how long previous frames took to render. Use this
     // estimate to decide when to wake up for EDS.
     int64_t frame_time_estimate =
-        frame_time_history_.GetSampleCount() == 0
-            ? GuessFrameTime(compositor_surfaces_.size())
-            : frame_time_history_.GetAverage();
+        frame_time_history.GetSampleCount() == 0
+            ? GuessFrameTime(compositor_surfaces.size())
+            : frame_time_history.GetAverage();
     frame_time_estimate = std::max(frame_time_estimate, kFrameTimeEstimateMin);
     DebugHudData::data.hwc_latency = frame_time_estimate;
 
@@ -902,9 +958,9 @@
 
         // There are several reasons we might skip a frame, but one possibility
         // is we mispredicted the frame time. Clear out the frame time history.
-        frame_time_history_.ResetWithSeed(
-            GuessFrameTime(compositor_surfaces_.size()));
-        frame_time_backlog_.clear();
+        frame_time_history.ResetWithSeed(
+            GuessFrameTime(compositor_surfaces.size()));
+        frame_time_backlog.clear();
         DebugHudData::data.hwc_frame_stats.SkipFrame();
 
         continue;
@@ -918,8 +974,6 @@
         error = SleepUntil(display_time_est - frame_time_estimate);
         ALOGE_IF(error < 0, "HardwareComposer::PostThread: Failed to sleep: %s",
                  strerror(-error));
-        if (error == kPostThreadInterrupted)
-          continue;
       }
     }
 
@@ -938,7 +992,7 @@
     // permanently backed up.
     PostLayers(layer_config_changed);
 
-    PostCompositorBuffers();
+    PostCompositorBuffers(compositor_surfaces);
 
     if (gpu_layer_ != nullptr) {
       // Note, with scanline racing, this draw is timed along with the post
@@ -946,88 +1000,55 @@
       LocalHandle frame_fence_fd;
       compositor_.DrawFrame(vsync_count_ + 1, &frame_fence_fd);
       if (frame_fence_fd) {
-        LOG_ALWAYS_FATAL_IF(frame_time_backlog_.size() >= kFrameTimeBacklogMax,
+        LOG_ALWAYS_FATAL_IF(frame_time_backlog.size() >= kFrameTimeBacklogMax,
                             "Frame time backlog exceeds capacity");
-        frame_time_backlog_.push_back(
+        frame_time_backlog.push_back(
             {frame_start_time, std::move(frame_fence_fd)});
       }
     } else if (!layer_config_changed) {
-      frame_time_history_.AddSample(GetSystemClockNs() - frame_start_time);
+      frame_time_history.AddSample(GetSystemClockNs() - frame_start_time);
     }
 
     HandlePendingScreenshots();
   }
+
+  // TODO(skiazyk): Currently the compositor is not fully releasing its EGL
+  // context, which seems to prevent the thread from exiting properly.
+  // This shouldn't be too hard to address, I just don't have time right now.
+  compositor_.Shutdown();
 }
 
-bool HardwareComposer::UpdateLayerConfig() {
-  std::vector<std::shared_ptr<DisplaySurface>> old_display_surfaces;
-  {
-    std::lock_guard<std::mutex> lock(post_thread_mutex_);
-    if (!active_surfaces_updated_)
-      return false;
-    old_display_surfaces = display_surfaces_;
-    display_surfaces_ = active_surfaces_;
-    active_surfaces_updated_ = false;
-  }
+bool HardwareComposer::UpdateLayerConfig(
+    std::vector<std::shared_ptr<DisplaySurface>>* compositor_surfaces) {
+  std::lock_guard<std::mutex> layer_lock(layer_mutex_);
 
+  if (!display_surfaces_updated_)
+    return false;
+
+  display_surfaces_updated_ = false;
   DebugHudData::data.ResetLayers();
 
-  // Figure out whether we need to update hardware layers. If this surface
-  // change does not add or remove hardware layers we can avoid display hiccups
-  // by gracefully updating only the GPU compositor layers.
-  int old_gpu_layer_count = 0;
-  int new_gpu_layer_count = 0;
-  bool hardware_layers_need_update = false;
-  // Look for new hardware layers and count new GPU layers.
-  for (const auto& surface : display_surfaces_) {
-    if (!(surface->flags() &
-          DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION))
-      ++new_gpu_layer_count;
-    else if (std::find(old_display_surfaces.begin(), old_display_surfaces.end(),
-                       surface) == old_display_surfaces.end())
-      // This is a new hardware layer, we need to update.
-      hardware_layers_need_update = true;
-  }
-  // Look for deleted hardware layers or compositor layers.
-  for (const auto& surface : old_display_surfaces) {
-    if (!(surface->flags() &
-          DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION))
-      ++old_gpu_layer_count;
-    else if (std::find(display_surfaces_.begin(), display_surfaces_.end(),
-                       surface) == display_surfaces_.end())
-      // This is a deleted hardware layer, we need to update.
-      hardware_layers_need_update = true;
-  }
-  // Check for compositor hardware layer transition.
-  if ((!old_gpu_layer_count && new_gpu_layer_count) ||
-      (old_gpu_layer_count && !new_gpu_layer_count))
-    hardware_layers_need_update = true;
-
-  // Set the chosen layer order for all surfaces.
-  for (size_t i = 0; i < display_surfaces_.size(); ++i) {
-    display_surfaces_[i]->SetLayerOrder(static_cast<int>(i));
-  }
-
   // Update compositor layers.
   {
     ATRACE_NAME("UpdateLayerConfig_GpuLayers");
     compositor_.UpdateSurfaces(display_surfaces_);
-    compositor_surfaces_.clear();
+    compositor_surfaces->clear();
     for (size_t i = 0; i < display_surfaces_.size(); ++i) {
       const auto& surface = display_surfaces_[i];
       if (!(surface->flags() &
             DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION)) {
-        compositor_surfaces_.push_back(surface);
+        compositor_surfaces->push_back(surface);
       }
     }
   }
 
-  if (!hardware_layers_need_update)
+  if (!hardware_layers_need_update_)
     return true;
 
   // Update hardware layers.
 
   ATRACE_NAME("UpdateLayerConfig_HwLayers");
+  hardware_layers_need_update_ = false;
 
   // Update the display layers in a non-destructive fashion.
 
@@ -1158,9 +1179,10 @@
   return true;
 }
 
-void HardwareComposer::PostCompositorBuffers() {
+void HardwareComposer::PostCompositorBuffers(
+    const std::vector<std::shared_ptr<DisplaySurface>>& compositor_surfaces) {
   ATRACE_NAME("PostCompositorBuffers");
-  for (const auto& surface : compositor_surfaces_) {
+  for (const auto& surface : compositor_surfaces) {
     compositor_.PostBuffer(surface);
   }
 }
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 2d3d78b..e2a8b90 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -176,12 +176,6 @@
 
 // HardwareComposer encapsulates the hardware composer HAL, exposing a
 // simplified API to post buffers to the display.
-//
-// HardwareComposer is accessed by both the vr flinger dispatcher thread and the
-// surface flinger main thread, in addition to internally running a separate
-// thread for compositing/EDS and posting layers to the HAL. When changing how
-// variables are used or adding new state think carefully about which threads
-// will access the state and whether it needs to be synchronized.
 class HardwareComposer {
  public:
   // Type for vsync callback.
@@ -199,12 +193,8 @@
 
   bool IsInitialized() const { return initialized_; }
 
-  // Start the post thread if there's work to do (i.e. visible layers). This
-  // should only be called from surface flinger's main thread.
-  void Enable();
-  // Pause the post thread, blocking until the post thread has signaled that
-  // it's paused. This should only be called from surface flinger's main thread.
-  void Disable();
+  bool Suspend();
+  bool Resume();
 
   // Get the HMD display metrics for the current display.
   DisplayMetrics GetHmdDisplayMetrics() const;
@@ -229,9 +219,12 @@
     return native_display_metrics_;
   }
 
+  std::shared_ptr<IonBuffer> framebuffer_target() const {
+    return framebuffer_target_;
+  }
+
   // Set the display surface stack to compose to the display each frame.
-  void SetDisplaySurfaces(
-      std::vector<std::shared_ptr<DisplaySurface>> surfaces);
+  int SetDisplaySurfaces(std::vector<std::shared_ptr<DisplaySurface>> surfaces);
 
   Compositor* GetCompositor() { return &compositor_; }
 
@@ -273,21 +266,8 @@
   void PostLayers(bool is_geometry_changed);
   void PostThread();
 
-  // Check to see if we have a value written to post_thread_interrupt_event_fd_,
-  // indicating a control thread interrupted the post thread. This clears the
-  // post_thread_interrupt_event_fd_ state in the process. Returns true if an
-  // interrupt was requested.
-  bool CheckPostThreadInterruptEventFd();
-  // Blocks until either event_fd becomes readable, or we're interrupted by a
-  // control thread. Any errors are returned as negative errno values. If we're
-  // interrupted, kPostThreadInterrupted will be returned.
-  int PostThreadPollInterruptible(int event_fd);
-
-  // BlockUntilVSync, WaitForVSync, and SleepUntil are all blocking calls made
-  // on the post thread that can be interrupted by a control thread. If
-  // interrupted, these calls return kPostThreadInterrupted.
   int ReadWaitPPState();
-  int BlockUntilVSync();
+  int BlockUntilVSync(/*out*/ bool* suspend_requested);
   int ReadVSyncTimestamp(int64_t* timestamp);
   int WaitForVSync(int64_t* timestamp);
   int SleepUntil(int64_t wakeup_timestamp);
@@ -295,18 +275,12 @@
   bool IsFramePendingInDriver() { return ReadWaitPPState() == 1; }
 
   // Returns true if the layer config changed, false otherwise
-  bool UpdateLayerConfig();
-  void PostCompositorBuffers();
+  bool UpdateLayerConfig(
+      std::vector<std::shared_ptr<DisplaySurface>>* compositor_surfaces);
+  void PostCompositorBuffers(
+      const std::vector<std::shared_ptr<DisplaySurface>>& compositor_surfaces);
 
-  // Return true if the post thread has work to do (i.e. there are visible
-  // surfaces to post to the screen). Must be called with post_thread_mutex_
-  // locked. Called only from the post thread.
-  bool PostThreadHasWork();
-
-  // Called on the post thread when the post thread is resumed.
-  void OnPostThreadResumed();
-  // Called on the post thread when the post thread is paused or quits.
-  void OnPostThreadPaused();
+  void UpdateDisplayState();
 
   struct FrameTimeMeasurementRecord {
     int64_t start_time;
@@ -350,28 +324,14 @@
   // Buffer for the background layer required by hardware composer.
   std::shared_ptr<IonBuffer> framebuffer_target_;
 
-  // Protects access to variables used by the post thread and one of the control
-  // threads (either the vr flinger dispatcher thread or the surface flinger
-  // main thread). This includes active_surfaces_, active_surfaces_updated_,
-  // post_thread_enabled_, post_thread_running_, and
-  // post_thread_quit_requested_.
-  std::mutex post_thread_mutex_;
+  // Protects access to the display surfaces and logical layers.
+  std::mutex layer_mutex_;
 
-  // Surfaces configured by the display manager. Written by the vr flinger
-  // dispatcher thread, read by the post thread.
-  std::vector<std::shared_ptr<DisplaySurface>> active_surfaces_;
-  // active_surfaces_updated_ is set to true by the vr flinger dispatcher thread
-  // when the list of active surfaces changes. active_surfaces_updated_ will be
-  // set back to false by the post thread when it processes the update.
-  bool active_surfaces_updated_;
-
-  // The surfaces displayed by the post thread. Used exclusively by the post
-  // thread.
+  // Active display surfaces configured by the display manager.
   std::vector<std::shared_ptr<DisplaySurface>> display_surfaces_;
-
-  // The surfaces rendered by the compositor. Used exclusively by the post
-  // thread.
-  std::vector<std::shared_ptr<DisplaySurface>> compositor_surfaces_;
+  std::vector<std::shared_ptr<DisplaySurface>> added_display_surfaces_;
+  bool display_surfaces_updated_;
+  bool hardware_layers_need_update_;
 
   // Layer array for handling buffer flow into hardware composer layers.
   // Note that the first array is the actual storage for the layer objects,
@@ -392,22 +352,31 @@
   // hand buffers to post processing and the results to hardware composer.
   std::thread post_thread_;
 
-  // Set to true if the post thread is allowed to run. Surface flinger and vr
-  // flinger share access to the display, and vr flinger shouldn't use the
-  // display while surface flinger is using it. While surface flinger owns the
-  // display, post_thread_enabled_ will be set to false to indicate the post
-  // thread shouldn't run.
-  bool post_thread_enabled_;
-  // Set to true by the post thread if it's currently running.
-  bool post_thread_running_;
-  // Set to true if the post thread should quit. Only set when destroying the
-  // HardwareComposer instance.
-  bool post_thread_quit_requested_;
-  // Used to wake the post thread up while it's waiting for vsync or sleeping
-  // until EDS preemption, for faster transition to the paused state.
-  pdx::LocalHandle post_thread_interrupt_event_fd_;
+  enum class PostThreadState {
+    // post_thread_state_ starts off paused. When suspending, the control thread
+    // will block until post_thread_state_ == kPaused, indicating the post
+    // thread has completed the transition to paused (most importantly: no more
+    // hardware composer calls).
+    kPaused,
+    // post_thread_state_ is set to kRunning by the control thread (either
+    // surface flinger's main thread or the vr flinger dispatcher thread). The
+    // post thread blocks until post_thread_state_ == kRunning.
+    kRunning,
+    // Set by the control thread to indicate the post thread should pause. The
+    // post thread will change post_thread_state_ from kPauseRequested to
+    // kPaused when it stops.
+    kPauseRequested
+  };
+  // Control variables to control the state of the post thread
+  PostThreadState post_thread_state_;
+  // Used to wake the post thread up while it's waiting for vsync, for faster
+  // transition to the paused state.
+  pdx::LocalHandle terminate_post_thread_event_fd_;
+  // post_thread_state_mutex_ should be held before checking or modifying
+  // post_thread_state_.
+  std::mutex post_thread_state_mutex_;
   // Used to communicate between the control thread and the post thread.
-  std::condition_variable post_thread_cond_var_;
+  std::condition_variable post_thread_state_cond_var_;
 
   // Backlight LED brightness sysfs node.
   pdx::LocalHandle backlight_brightness_fd_;
@@ -441,17 +410,6 @@
   // out to display frame boundaries, so we need to tell it about vsyncs.
   DvrPose* pose_client_;
 
-  // Our history of frame times. This is used to get a better estimate of how
-  // long the next frame will take, to set a schedule for EDS.
-  FrameTimeHistory frame_time_history_;
-
-  // The backlog is used to allow us to start rendering the next frame before
-  // the previous frame has finished, and still get an accurate measurement of
-  // frame duration.
-  std::vector<FrameTimeMeasurementRecord> frame_time_backlog_;
-
-  static constexpr int kPostThreadInterrupted = 1;
-
   static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display);
   static void HwcVSync(hwc2_callback_data_t data, hwc2_display_t display,
                        int64_t timestamp);
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 145852e..17dce96 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -4,9 +4,6 @@
 #include <thread>
 #include <memory>
 
-#include <pdx/default_transport/service_dispatcher.h>
-#include <vr/vr_manager/vr_manager.h>
-
 namespace android {
 
 namespace Hwc2 {
@@ -19,39 +16,16 @@
 
 class VrFlinger {
  public:
-  using RequestDisplayCallback = std::function<void(bool)>;
-  static std::unique_ptr<VrFlinger> Create(
-      Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback);
-  ~VrFlinger();
+  VrFlinger();
+  int Run(Hwc2::Composer* hidl);
 
-  // These functions are all called on surface flinger's main thread.
-  void OnBootFinished();
-  void GrantDisplayOwnership();
-  void SeizeDisplayOwnership();
-
-  // Called on a binder thread.
+  void EnterVrMode();
+  void ExitVrMode();
   void OnHardwareComposerRefresh();
 
  private:
-  VrFlinger();
-  bool Init(Hwc2::Composer* hidl,
-            RequestDisplayCallback request_display_callback);
-
-  // Needs to be a separate class for binder's ref counting
-  class PersistentVrStateCallback : public BnPersistentVrStateCallbacks {
-   public:
-    PersistentVrStateCallback(RequestDisplayCallback request_display_callback)
-        : request_display_callback_(request_display_callback) {}
-    void onPersistentVrStateChanged(bool enabled) override;
-   private:
-    RequestDisplayCallback request_display_callback_;
-  };
-
-  std::thread dispatcher_thread_;
-  std::unique_ptr<android::pdx::ServiceDispatcher> dispatcher_;
+  std::thread displayd_thread_;
   std::shared_ptr<android::dvr::DisplayService> display_service_;
-  sp<PersistentVrStateCallback> persistent_vr_state_callback_;
-  RequestDisplayCallback request_display_callback_;
 };
 
 } // namespace dvr
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 21226db..9163e71 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -9,13 +9,11 @@
 #include <unistd.h>
 #include <memory>
 
-#include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <log/log.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
 #include <private/dvr/display_client.h>
-#include <sys/prctl.h>
 #include <sys/resource.h>
 
 #include <pdx/default_transport/service_dispatcher.h>
@@ -31,37 +29,11 @@
 namespace android {
 namespace dvr {
 
-std::unique_ptr<VrFlinger> VrFlinger::Create(
-    Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) {
-  std::unique_ptr<VrFlinger> vr_flinger(new VrFlinger);
-  if (vr_flinger->Init(hidl, request_display_callback))
-    return vr_flinger;
-  else
-    return nullptr;
-}
-
 VrFlinger::VrFlinger() {}
 
-VrFlinger::~VrFlinger() {
-  if (persistent_vr_state_callback_.get()) {
-    sp<IVrManager> vr_manager = interface_cast<IVrManager>(
-        defaultServiceManager()->checkService(String16("vrmanager")));
-    if (vr_manager.get()) {
-      vr_manager->unregisterPersistentVrStateListener(
-          persistent_vr_state_callback_);
-    }
-  }
-
-  if (dispatcher_)
-    dispatcher_->SetCanceled(true);
-  if (dispatcher_thread_.joinable())
-    dispatcher_thread_.join();
-}
-
-bool VrFlinger::Init(Hwc2::Composer* hidl,
-                     RequestDisplayCallback request_display_callback) {
-  if (!hidl || !request_display_callback)
-    return false;
+int VrFlinger::Run(Hwc2::Composer* hidl) {
+  if (!hidl)
+    return EINVAL;
 
   std::shared_ptr<android::pdx::Service> service;
 
@@ -75,27 +47,25 @@
 
   android::ProcessState::self()->startThreadPool();
 
-  request_display_callback_ = request_display_callback;
-
-  dispatcher_ =
+  std::shared_ptr<android::pdx::ServiceDispatcher> dispatcher =
       android::pdx::default_transport::ServiceDispatcher::Create();
-  CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher.");
+  CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher.");
 
   display_service_ = android::dvr::DisplayService::Create(hidl);
   CHECK_ERROR(!display_service_, error, "Failed to create display service.");
-  dispatcher_->AddService(display_service_);
+  dispatcher->AddService(display_service_);
 
   service = android::dvr::DisplayManagerService::Create(display_service_);
   CHECK_ERROR(!service, error, "Failed to create display manager service.");
-  dispatcher_->AddService(service);
+  dispatcher->AddService(service);
 
   service = android::dvr::ScreenshotService::Create();
   CHECK_ERROR(!service, error, "Failed to create screenshot service.");
-  dispatcher_->AddService(service);
+  dispatcher->AddService(service);
 
   service = android::dvr::VSyncService::Create();
   CHECK_ERROR(!service, error, "Failed to create vsync service.");
-  dispatcher_->AddService(service);
+  dispatcher->AddService(service);
 
   display_service_->SetVSyncCallback(
       std::bind(&android::dvr::VSyncService::VSyncEvent,
@@ -103,51 +73,45 @@
                 std::placeholders::_1, std::placeholders::_2,
                 std::placeholders::_3, std::placeholders::_4));
 
-  dispatcher_thread_ = std::thread([this]() {
-    prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
+  displayd_thread_ = std::thread([this, dispatcher]() {
     ALOGI("Entering message loop.");
 
-    int ret = dispatcher_->EnterDispatchLoop();
+    int ret = dispatcher->EnterDispatchLoop();
     if (ret < 0) {
       ALOGE("Dispatch loop exited because: %s\n", strerror(-ret));
     }
   });
 
-  return true;
+  return NO_ERROR;
 
 error:
-  return false;
+  display_service_.reset();
+
+  return -1;
 }
 
-void VrFlinger::OnBootFinished() {
-  sp<IVrManager> vr_manager = interface_cast<IVrManager>(
-      defaultServiceManager()->checkService(String16("vrmanager")));
-  if (vr_manager.get()) {
-    persistent_vr_state_callback_ =
-        new PersistentVrStateCallback(request_display_callback_);
-    vr_manager->registerPersistentVrStateListener(
-        persistent_vr_state_callback_);
+void VrFlinger::EnterVrMode() {
+  if (display_service_) {
+    display_service_->SetActive(true);
   } else {
-    ALOGE("Unable to register vr flinger for persistent vr mode changes");
+    ALOGE("Failed to enter VR mode : Display service is not started.");
   }
 }
 
-void VrFlinger::GrantDisplayOwnership() {
-  display_service_->GrantDisplayOwnership();
-}
-
-void VrFlinger::SeizeDisplayOwnership() {
-  display_service_->SeizeDisplayOwnership();
+void VrFlinger::ExitVrMode() {
+  if (display_service_) {
+    display_service_->SetActive(false);
+  } else {
+    ALOGE("Failed to exit VR mode : Display service is not started.");
+  }
 }
 
 void VrFlinger::OnHardwareComposerRefresh() {
-  display_service_->OnHardwareComposerRefresh();
-}
-
-void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged(
-    bool enabled) {
-  ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off");
-  request_display_callback_(enabled);
+  if (display_service_) {
+    display_service_->OnHardwareComposerRefresh();
+  } else {
+    ALOGE("OnHardwareComposerRefresh failed : Display service is not started.");
+  }
 }
 
 }  // namespace dvr