Merge "Revert "Revert "Tie vr flinger to persistent vr mode"""
diff --git a/include/vr/vr_manager/vr_manager.h b/include/vr/vr_manager/vr_manager.h
index 0c5da19..9df2c6b 100644
--- a/include/vr/vr_manager/vr_manager.h
+++ b/include/vr/vr_manager/vr_manager.h
@@ -41,6 +41,28 @@
 };
 
 
+// Must be kept in sync with interface defined in
+// IPersistentVrStateCallbacks.aidl.
+
+class IPersistentVrStateCallbacks : public IInterface {
+public:
+    DECLARE_META_INTERFACE(PersistentVrStateCallbacks)
+
+    virtual void onPersistentVrStateChanged(bool enabled) = 0;
+};
+
+enum PersistentVrStateCallbacksTransaction {
+    ON_PERSISTENT_VR_STATE_CHANGED = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BnPersistentVrStateCallbacks
+        : public BnInterface<IPersistentVrStateCallbacks> {
+public:
+    status_t onTransact(uint32_t code, const Parcel& data,
+                        Parcel* reply, uint32_t flags = 0) override;
+};
+
+
 // Must be kept in sync with interface defined in IVrManager.aidl.
 
 class IVrManager : public IInterface {
@@ -49,12 +71,18 @@
 
     virtual void registerListener(const sp<IVrStateCallbacks>& cb) = 0;
     virtual void unregisterListener(const sp<IVrStateCallbacks>& cb) = 0;
+    virtual void registerPersistentVrStateListener(
+        const sp<IPersistentVrStateCallbacks>& cb) = 0;
+    virtual void unregisterPersistentVrStateListener(
+        const sp<IPersistentVrStateCallbacks>& cb) = 0;
     virtual bool getVrModeState() = 0;
 };
 
 enum VrManagerTransaction {
     REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
     UNREGISTER_LISTENER,
+    REGISTER_PERSISTENT_VR_STATE_LISTENER,
+    UNREGISTER_PERSISTENT_VR_STATE_LISTENER,
     GET_VR_MODE_STATE,
 };
 
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 3a1cc72..50d95f7 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -248,29 +248,6 @@
   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 bfc167e..f579a8c 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -105,9 +105,6 @@
   // 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 e373123..7a2986a 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
@@ -217,8 +217,6 @@
     kOpGetMetadataBuffer,
     kOpCreateVideoMeshSurface,
     kOpVideoMeshSurfaceCreateProducerQueue,
-    kOpEnterVrMode,
-    kOpExitVrMode,
     kOpSetViewerParams,
     kOpGetPoseBuffer,
   };
@@ -246,8 +244,6 @@
   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));
   PDX_REMOTE_METHOD(GetPoseBuffer, kOpGetPoseBuffer,
diff --git a/libs/vr/libvr_manager/vr_manager.cpp b/libs/vr/libvr_manager/vr_manager.cpp
index d24cbb5..5cfc22e 100644
--- a/libs/vr/libvr_manager/vr_manager.cpp
+++ b/libs/vr/libvr_manager/vr_manager.cpp
@@ -53,6 +53,40 @@
   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> {
@@ -74,6 +108,22 @@
     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 e3d7564..da7281b 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -30,7 +30,8 @@
 namespace android {
 namespace dvr {
 
-DisplayService::DisplayService() : DisplayService(nullptr) {}
+DisplayService::DisplayService()
+    : DisplayService(nullptr) {}
 
 DisplayService::DisplayService(Hwc2::Composer* hidl)
     : BASE("DisplayService", Endpoint::Create(DisplayRPC::kClientPath)),
@@ -83,16 +84,6 @@
           *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);
@@ -196,16 +187,6 @@
   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();
@@ -313,7 +294,7 @@
   return visible_surfaces;
 }
 
-int DisplayService::UpdateActiveDisplaySurfaces() {
+void DisplayService::UpdateActiveDisplaySurfaces() {
   auto visible_surfaces = GetVisibleDisplaySurfaces();
 
   // Sort the surfaces based on manager z order first, then client z order.
@@ -344,7 +325,8 @@
     if (surface->client_blur_behind())
       blur_requested = true;
   }
-  return hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
+
+  hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
 }
 
 pdx::BorrowedChannelHandle DisplayService::SetupPoseBuffer(
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index a2b3ed5..2a71b4a 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.
-  int UpdateActiveDisplaySurfaces();
+  void UpdateActiveDisplaySurfaces();
 
   pdx::BorrowedChannelHandle SetupPoseBuffer(size_t extended_region_size,
                                              int usage);
@@ -63,13 +63,8 @@
     return hardware_composer_.display_metrics();
   }
 
-  void SetActive(bool activated) {
-    if (activated) {
-      hardware_composer_.Resume();
-    } else {
-      hardware_composer_.Suspend();
-    }
-  }
+  void GrantDisplayOwnership() { hardware_composer_.Enable(); }
+  void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
 
   void OnHardwareComposerRefresh();
 
@@ -88,8 +83,6 @@
 
   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);
   pdx::LocalChannelHandle OnGetPoseBuffer(pdx::Message& message);
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 53c2ac2..da45859 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -103,12 +103,13 @@
     : initialized_(false),
       hwc2_hidl_(hwc2_hidl),
       display_transform_(HWC_TRANSFORM_NONE),
-      display_surfaces_updated_(false),
-      hardware_layers_need_update_(false),
+      active_surfaces_updated_(false),
       active_layer_count_(0),
       gpu_layer_(nullptr),
-      post_thread_state_(PostThreadState::kPaused),
-      terminate_post_thread_event_fd_(-1),
+      post_thread_enabled_(false),
+      post_thread_running_(false),
+      post_thread_quit_requested_(false),
+      post_thread_interrupt_event_fd_(-1),
       backlight_brightness_fd_(-1),
       primary_display_vsync_event_fd_(-1),
       primary_display_wait_pp_fd_(-1),
@@ -124,7 +125,12 @@
 }
 
 HardwareComposer::~HardwareComposer(void) {
-  Suspend();
+  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();
+  }
 }
 
 bool HardwareComposer::Initialize() {
@@ -167,24 +173,56 @@
   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_;
 }
 
-bool HardwareComposer::Resume() {
-  std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
-  if (post_thread_state_ == PostThreadState::kRunning) {
-    return false;
+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));
   }
+}
 
-  std::lock_guard<std::mutex> layer_lock(layer_mutex_);
+bool HardwareComposer::PostThreadHasWork() {
+  return !display_surfaces_.empty() ||
+      (active_surfaces_updated_ && !active_surfaces_.empty());
+}
 
-  int32_t ret = HWC2_ERROR_NONE;
-
-  // Always turn off vsync when we start.
-  EnableVsync(false);
-
+void HardwareComposer::OnPostThreadResumed() {
   constexpr int format = HAL_PIXEL_FORMAT_RGBA_8888;
   constexpr int usage =
       GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER;
@@ -198,97 +236,33 @@
     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");
 
-  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));
+  EnableVsync(true);
 
-  post_thread_state_ = PostThreadState::kRunning;
-  post_thread_state_cond_var_.notify_all();
+  // 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);
 
-  // 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();
-  }
+  // Initialize the GPU compositor.
+  LOG_ALWAYS_FATAL_IF(!compositor_.Initialize(GetHmdDisplayMetrics()),
+                      "Failed to initialize the compositor");
 
-  return true;
+  // Trigger target-specific performance mode change.
+  property_set(kDvrPerformanceProperty, "performance");
 }
 
-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();
+void HardwareComposer::OnPostThreadPaused() {
   retire_fence_fds_.clear();
   gpu_layer_ = nullptr;
 
-  // We have to destroy the layers before we close the hwc device
+  // We have to destroy the layers to fully clear hwc device state before
+  // handing off back to surface flinger
   for (size_t i = 0; i < kMaxHardwareLayers; ++i) {
     layers_[i]->Reset();
   }
@@ -297,12 +271,26 @@
 
   framebuffer_target_.reset();
 
-  //hwc2_hidl_.reset();
+  display_surfaces_.clear();
+  compositor_surfaces_.clear();
 
-  if (pose_client_)
+  // Since we're clearing display_surfaces_ we'll need an update.
+  active_surfaces_updated_ = true;
+
+  if (pose_client_) {
     dvrPoseDestroy(pose_client_);
+    pose_client_ = nullptr;
+  }
 
-  return true;
+  EnableVsync(false);
+
+  frame_time_history_.ResetWithSeed(GuessFrameTime(0));
+  frame_time_backlog_.clear();
+
+  compositor_.Shutdown();
+
+  // Trigger target-specific performance mode change.
+  property_set(kDvrPerformanceProperty, "idle");
 }
 
 DisplayMetrics HardwareComposer::GetHmdDisplayMetrics() const {
@@ -519,82 +507,48 @@
   }
 }
 
-// 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::SetDisplaySurfaces(
+void 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_);
-
   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();
+}
 
-  // 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;
+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);
+
+  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;
   }
-  // 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
@@ -690,35 +644,8 @@
 // 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(/*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;
+int HardwareComposer::BlockUntilVSync() {
+  return PostThreadPollInterruptible(primary_display_vsync_event_fd_.Get());
 }
 
 // Waits for the next vsync and returns the timestamp of the vsync event. If
@@ -740,9 +667,8 @@
 
     if (error == -EAGAIN) {
       // Vsync was turned off, wait for the next vsync event.
-      bool suspend_requested = false;
-      error = BlockUntilVSync(&suspend_requested);
-      if (error < 0 || suspend_requested)
+      error = BlockUntilVSync();
+      if (error < 0 || error == kPostThreadInterrupted)
         return error;
 
       // Try again to get the timestamp for this new vsync interval.
@@ -765,13 +691,14 @@
 
     if (distance_to_vsync_est > threshold_ns) {
       // Wait for vsync event notification.
-      bool suspend_requested = false;
-      error = BlockUntilVSync(&suspend_requested);
-      if (error < 0 || suspend_requested)
+      error = BlockUntilVSync();
+      if (error < 0 || error == kPostThreadInterrupted)
         return error;
     } else {
-      // Sleep for a short time before retrying.
-      std::this_thread::sleep_for(std::chrono::milliseconds(1));
+      // Sleep for a short time (1 millisecond) before retrying.
+      error = SleepUntil(GetSystemClockNs() + 1000000);
+      if (error < 0 || error == kPostThreadInterrupted)
+        return error;
     }
   }
 }
@@ -791,21 +718,12 @@
     return -error;
   }
 
-  // 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;
+  return PostThreadPollInterruptible(timer_fd);
 }
 
 void HardwareComposer::PostThread() {
   // NOLINTNEXTLINE(runtime/int)
-  prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("PostThread"), 0, 0, 0);
+  prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrHwcPost"), 0, 0, 0);
 
   // Set the scheduler to SCHED_FIFO with high priority.
   int error = dvrSetSchedulerClass(0, "graphics:high");
@@ -819,12 +737,40 @@
       "HardwareComposer::PostThread: Failed to set cpu partition: %s",
       strerror(-error));
 
-  // Force the layers to be setup at least once.
-  display_surfaces_updated_ = true;
+#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
 
-  // Initialize the GPU compositor.
-  LOG_ALWAYS_FATAL_IF(!compositor_.Initialize(GetHmdDisplayMetrics()),
-                      "Failed to initialize the compositor");
+  // 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));
 
   const int64_t ns_per_frame = display_metrics_.vsync_period_ns;
   const int64_t photon_offset_ns = GetPosePredictionTimeOffset(ns_per_frame);
@@ -838,41 +784,48 @@
   right_eye_photon_offset_ns =
       property_get_int64(kRightEyeOffsetProperty, right_eye_photon_offset_ns);
 
-  // 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);
+  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> 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;
+      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);
       }
+      post_thread_running_ = true;
+    }
+
+    if (!was_running) {
+      ALOGI("VrHwcPost thread resumed");
+      OnPostThreadResumed();
+      was_running = true;
     }
 
     int64_t vsync_timestamp = 0;
@@ -887,22 +840,13 @@
           error < 0,
           "HardwareComposer::PostThread: Failed to wait for vsync event: %s",
           strerror(-error));
-
       // Don't bother processing this frame if a pause was requested
-      std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
-      if (post_thread_state_ == PostThreadState::kPauseRequested) {
+      if (error == kPostThreadInterrupted)
         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.
@@ -911,24 +855,24 @@
                                 ns_per_frame, right_eye_photon_offset_ns);
     }
 
-    bool layer_config_changed = UpdateLayerConfig(&compositor_surfaces);
+    bool layer_config_changed = UpdateLayerConfig();
 
-    if (layer_config_changed) {
-      frame_time_history.ResetWithSeed(
-          GuessFrameTime(compositor_surfaces.size()));
-      frame_time_backlog.clear();
+    if (!was_running || 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;
 
@@ -958,9 +902,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;
@@ -974,6 +918,8 @@
         error = SleepUntil(display_time_est - frame_time_estimate);
         ALOGE_IF(error < 0, "HardwareComposer::PostThread: Failed to sleep: %s",
                  strerror(-error));
+        if (error == kPostThreadInterrupted)
+          continue;
       }
     }
 
@@ -992,7 +938,7 @@
     // permanently backed up.
     PostLayers(layer_config_changed);
 
-    PostCompositorBuffers(compositor_surfaces);
+    PostCompositorBuffers();
 
     if (gpu_layer_ != nullptr) {
       // Note, with scanline racing, this draw is timed along with the post
@@ -1000,55 +946,88 @@
       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>>* compositor_surfaces) {
-  std::lock_guard<std::mutex> layer_lock(layer_mutex_);
+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;
+  }
 
-  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.
 
@@ -1179,10 +1158,9 @@
   return true;
 }
 
-void HardwareComposer::PostCompositorBuffers(
-    const std::vector<std::shared_ptr<DisplaySurface>>& compositor_surfaces) {
+void HardwareComposer::PostCompositorBuffers() {
   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 e2a8b90..2d3d78b 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -176,6 +176,12 @@
 
 // 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.
@@ -193,8 +199,12 @@
 
   bool IsInitialized() const { return initialized_; }
 
-  bool Suspend();
-  bool Resume();
+  // 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();
 
   // Get the HMD display metrics for the current display.
   DisplayMetrics GetHmdDisplayMetrics() const;
@@ -219,12 +229,9 @@
     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.
-  int SetDisplaySurfaces(std::vector<std::shared_ptr<DisplaySurface>> surfaces);
+  void SetDisplaySurfaces(
+      std::vector<std::shared_ptr<DisplaySurface>> surfaces);
 
   Compositor* GetCompositor() { return &compositor_; }
 
@@ -266,8 +273,21 @@
   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(/*out*/ bool* suspend_requested);
+  int BlockUntilVSync();
   int ReadVSyncTimestamp(int64_t* timestamp);
   int WaitForVSync(int64_t* timestamp);
   int SleepUntil(int64_t wakeup_timestamp);
@@ -275,12 +295,18 @@
   bool IsFramePendingInDriver() { return ReadWaitPPState() == 1; }
 
   // Returns true if the layer config changed, false otherwise
-  bool UpdateLayerConfig(
-      std::vector<std::shared_ptr<DisplaySurface>>* compositor_surfaces);
-  void PostCompositorBuffers(
-      const std::vector<std::shared_ptr<DisplaySurface>>& compositor_surfaces);
+  bool UpdateLayerConfig();
+  void PostCompositorBuffers();
 
-  void UpdateDisplayState();
+  // 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();
 
   struct FrameTimeMeasurementRecord {
     int64_t start_time;
@@ -324,14 +350,28 @@
   // Buffer for the background layer required by hardware composer.
   std::shared_ptr<IonBuffer> framebuffer_target_;
 
-  // Protects access to the display surfaces and logical layers.
-  std::mutex layer_mutex_;
+  // 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_;
 
-  // Active display surfaces configured by the display manager.
+  // 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.
   std::vector<std::shared_ptr<DisplaySurface>> display_surfaces_;
-  std::vector<std::shared_ptr<DisplaySurface>> added_display_surfaces_;
-  bool display_surfaces_updated_;
-  bool hardware_layers_need_update_;
+
+  // The surfaces rendered by the compositor. Used exclusively by the post
+  // thread.
+  std::vector<std::shared_ptr<DisplaySurface>> compositor_surfaces_;
 
   // Layer array for handling buffer flow into hardware composer layers.
   // Note that the first array is the actual storage for the layer objects,
@@ -352,31 +392,22 @@
   // hand buffers to post processing and the results to hardware composer.
   std::thread post_thread_;
 
-  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_;
+  // 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_;
   // Used to communicate between the control thread and the post thread.
-  std::condition_variable post_thread_state_cond_var_;
+  std::condition_variable post_thread_cond_var_;
 
   // Backlight LED brightness sysfs node.
   pdx::LocalHandle backlight_brightness_fd_;
@@ -410,6 +441,17 @@
   // 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 17dce96..145852e 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -4,6 +4,9 @@
 #include <thread>
 #include <memory>
 
+#include <pdx/default_transport/service_dispatcher.h>
+#include <vr/vr_manager/vr_manager.h>
+
 namespace android {
 
 namespace Hwc2 {
@@ -16,16 +19,39 @@
 
 class VrFlinger {
  public:
-  VrFlinger();
-  int Run(Hwc2::Composer* hidl);
+  using RequestDisplayCallback = std::function<void(bool)>;
+  static std::unique_ptr<VrFlinger> Create(
+      Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback);
+  ~VrFlinger();
 
-  void EnterVrMode();
-  void ExitVrMode();
+  // These functions are all called on surface flinger's main thread.
+  void OnBootFinished();
+  void GrantDisplayOwnership();
+  void SeizeDisplayOwnership();
+
+  // Called on a binder thread.
   void OnHardwareComposerRefresh();
 
  private:
-  std::thread displayd_thread_;
+  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::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 9163e71..21226db 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -9,11 +9,13 @@
 #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>
@@ -29,11 +31,37 @@
 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() {}
 
-int VrFlinger::Run(Hwc2::Composer* hidl) {
-  if (!hidl)
-    return EINVAL;
+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;
 
   std::shared_ptr<android::pdx::Service> service;
 
@@ -47,25 +75,27 @@
 
   android::ProcessState::self()->startThreadPool();
 
-  std::shared_ptr<android::pdx::ServiceDispatcher> dispatcher =
+  request_display_callback_ = request_display_callback;
+
+  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,
@@ -73,45 +103,51 @@
                 std::placeholders::_1, std::placeholders::_2,
                 std::placeholders::_3, std::placeholders::_4));
 
-  displayd_thread_ = std::thread([this, dispatcher]() {
+  dispatcher_thread_ = std::thread([this]() {
+    prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
     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 NO_ERROR;
+  return true;
 
 error:
-  display_service_.reset();
-
-  return -1;
+  return false;
 }
 
-void VrFlinger::EnterVrMode() {
-  if (display_service_) {
-    display_service_->SetActive(true);
+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_);
   } else {
-    ALOGE("Failed to enter VR mode : Display service is not started.");
+    ALOGE("Unable to register vr flinger for persistent vr mode changes");
   }
 }
 
-void VrFlinger::ExitVrMode() {
-  if (display_service_) {
-    display_service_->SetActive(false);
-  } else {
-    ALOGE("Failed to exit VR mode : Display service is not started.");
-  }
+void VrFlinger::GrantDisplayOwnership() {
+  display_service_->GrantDisplayOwnership();
+}
+
+void VrFlinger::SeizeDisplayOwnership() {
+  display_service_->SeizeDisplayOwnership();
 }
 
 void VrFlinger::OnHardwareComposerRefresh() {
-  if (display_service_) {
-    display_service_->OnHardwareComposerRefresh();
-  } else {
-    ALOGE("OnHardwareComposerRefresh failed : Display service is not started.");
-  }
+  display_service_->OnHardwareComposerRefresh();
+}
+
+void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged(
+    bool enabled) {
+  ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off");
+  request_display_callback_(enabled);
 }
 
 }  // namespace dvr
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index a6ea750..c87a8d9 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -53,7 +53,6 @@
     LOCAL_CFLAGS += -DUSE_HWC2
     LOCAL_SRC_FILES += \
         SurfaceFlinger.cpp \
-        VrStateCallbacks.cpp \
         DisplayHardware/HWComposer.cpp
     ifeq ($(TARGET_USES_HWC2ON1ADAPTER), true)
         LOCAL_CFLAGS += -DBYPASS_IHWC
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4e7e36f..9df49f6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -73,7 +73,6 @@
 #include "LayerDim.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
-#include "VrStateCallbacks.h"
 
 #include "DisplayHardware/FramebufferSurface.h"
 #include "DisplayHardware/HWComposer.h"
@@ -118,6 +117,7 @@
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
 bool SurfaceFlinger::hasSyncFramework;
+bool SurfaceFlinger::useVrFlinger;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -136,7 +136,6 @@
         mVisibleRegionsDirty(false),
         mGeometryInvalid(false),
         mAnimCompositionPending(false),
-        mVrModeSupported(0),
         mDebugRegion(0),
         mDebugDDMS(0),
         mDebugDisableHWC(0),
@@ -156,10 +155,8 @@
         mFrameBuckets(),
         mTotalTime(0),
         mLastSwapTime(0),
-        mNumLayers(0)
-#ifdef USE_HWC2
-        ,mEnterVrMode(false)
-#endif
+        mNumLayers(0),
+        mVrFlingerRequestsDisplay(false)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -184,13 +181,13 @@
     maxVirtualDisplaySize = getUInt64<ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::maxVirtualDisplaySize>(0);
 
+    // Vr flinger is only enabled on Daydream ready devices.
+    useVrFlinger = getBool< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::useVrFlinger>(false);
+
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
 
-    // TODO (urbanus): remove once b/35319396 is fixed.
-    property_get("ro.boot.vr", value, "0");
-    mVrModeSupported = atoi(value);
-
     property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
     mGpuToCpuSupported = !atoi(value);
 
@@ -231,14 +228,6 @@
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     eglTerminate(display);
-
-    if (mVrStateCallbacks.get()) {
-        sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
-            defaultServiceManager()->checkService(String16("vrmanager")));
-        if (vrManagerService.get()) {
-            vrManagerService->unregisterListener(mVrStateCallbacks);
-        }
-    }
 }
 
 void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
@@ -365,6 +354,10 @@
         window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
     }
 
+    if (mVrFlinger) {
+      mVrFlinger->OnBootFinished();
+    }
+
     // stop boot animation
     // formerly we would just kill the process, but we now ask it to exit so it
     // can choose where to stop the animation.
@@ -373,13 +366,6 @@
     const int LOGTAG_SF_STOP_BOOTANIM = 60110;
     LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
                    ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
-
-    sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
-        defaultServiceManager()->checkService(String16("vrmanager")));
-    if (vrManagerService.get()) {
-        mVrStateCallbacks = new VrStateCallbacks(*this);
-        vrManagerService->registerListener(mVrStateCallbacks);
-    }
 }
 
 void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -575,13 +561,26 @@
     // Drop the state lock while we initialize the hardware composer. We drop
     // the lock because on creation, it will call back into SurfaceFlinger to
     // initialize the primary display.
-    LOG_ALWAYS_FATAL_IF(mEnterVrMode, "Starting in vr mode is not currently supported.");
+    LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
+        "Starting with vr flinger active is not currently supported.");
     mRealHwc = new HWComposer(false);
     mHwc = mRealHwc;
     mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
 
     Mutex::Autolock _l(mStateLock);
 
+    if (useVrFlinger) {
+        auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
+            mVrFlingerRequestsDisplay = requestDisplay;
+            signalTransaction();
+        };
+        mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(),
+                                            vrFlingerRequestDisplayCallback);
+        if (!mVrFlinger) {
+            ALOGE("Failed to start vrflinger");
+        }
+    }
+
     // retrieve the EGL context that was selected/created
     mEGLContext = mRenderEngine->getEGLContext();
 
@@ -1196,14 +1195,17 @@
     // transition.
     mDrawingState.displays.clear();
     mDisplays.clear();
+    initializeDisplays();
 }
 
-void SurfaceFlinger::updateVrMode() {
-    bool enteringVrMode = mEnterVrMode;
-    if (enteringVrMode == mHwc->isUsingVrComposer()) {
+void SurfaceFlinger::updateVrFlinger() {
+    if (!mVrFlinger)
+        return;
+    bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
+    if (vrFlingerRequestsDisplay == mHwc->isUsingVrComposer()) {
         return;
     }
-    if (enteringVrMode && !mVrHwc) {
+    if (vrFlingerRequestsDisplay && !mVrHwc) {
         // Construct new HWComposer without holding any locks.
         mVrHwc = new HWComposer(true);
         ALOGV("Vr HWC created");
@@ -1211,25 +1213,13 @@
     {
         Mutex::Autolock _l(mStateLock);
 
-        if (enteringVrMode) {
-            // Start vrflinger thread, if it hasn't been started already.
-            if (!mVrFlinger) {
-                mVrFlinger = std::make_unique<dvr::VrFlinger>();
-                int err = mVrFlinger->Run(mHwc->getComposer());
-                if (err != NO_ERROR) {
-                    ALOGE("Failed to run vrflinger: %s (%d)", strerror(-err), err);
-                    mVrFlinger.reset();
-                    mEnterVrMode = false;
-                    return;
-                }
-            }
-
+        if (vrFlingerRequestsDisplay) {
             resetHwc();
 
             mHwc = mVrHwc;
-            mVrFlinger->EnterVrMode();
+            mVrFlinger->GrantDisplayOwnership();
         } else {
-            mVrFlinger->ExitVrMode();
+            mVrFlinger->SeizeDisplayOwnership();
 
             resetHwc();
 
@@ -1251,12 +1241,6 @@
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
-            // TODO(eieio): Tied to a conditional until SELinux issues
-            // are resolved.
-            if (mVrModeSupported) {
-                updateVrMode();
-            }
-
             bool frameMissed = !mHadClientComposition &&
                     mPreviousPresentFence != Fence::NO_FENCE &&
                     (mPreviousPresentFence->getSignalTime() ==
@@ -1268,6 +1252,11 @@
                 break;
             }
 
+            // Now that we're going to make it to the handleMessageTransaction()
+            // call below it's safe to call updateVrFlinger(), which will
+            // potentially trigger a display handoff.
+            updateVrFlinger();
+
             bool refreshNeeded = handleMessageTransaction();
             refreshNeeded |= handleMessageInvalidate();
             refreshNeeded |= mRepaintEverything;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7d7d4ff..2a24cb2 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -84,7 +84,6 @@
 class EventControlThread;
 class VSyncSource;
 class InjectVSyncSource;
-class VrStateCallbacks;
 
 namespace dvr {
 class VrFlinger;
@@ -211,7 +210,6 @@
     friend class EventThread;
     friend class Layer;
     friend class MonitoredProducer;
-    friend class VrStateCallbacks;
 
     // This value is specified in number of frames.  Log frame stats at most
     // every half hour.
@@ -530,9 +528,8 @@
     void clearHwcLayers(const LayerVector& layers);
     void resetHwc();
 
-    // Check to see if we should change to or from vr mode, and if so, perform
-    // the handoff.
-    void updateVrMode();
+    // Check to see if we should handoff to vr flinger.
+    void updateVrFlinger();
 #endif
 
     /* ------------------------------------------------------------------------
@@ -602,7 +599,6 @@
     DefaultKeyedVector< wp<IBinder>, sp<DisplayDevice> > mDisplays;
 
     // don't use a lock for these, we don't care
-    int mVrModeSupported;
     int mDebugRegion;
     int mDebugDDMS;
     int mDebugDisableHWC;
@@ -699,9 +695,8 @@
     status_t CheckTransactCodeCredentials(uint32_t code);
 
 #ifdef USE_HWC2
-    sp<VrStateCallbacks> mVrStateCallbacks;
-
-    std::atomic<bool> mEnterVrMode;
+    std::atomic<bool> mVrFlingerRequestsDisplay;
+    static bool useVrFlinger;
 #endif
     };
 }; // namespace android
diff --git a/services/surfaceflinger/VrStateCallbacks.cpp b/services/surfaceflinger/VrStateCallbacks.cpp
deleted file mode 100644
index a924def..0000000
--- a/services/surfaceflinger/VrStateCallbacks.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "VrStateCallbacks.h"
-#include "SurfaceFlinger.h"
-
-namespace android {
-
-VrStateCallbacks::VrStateCallbacks(SurfaceFlinger& flinger)
-    : mFlinger(flinger) {}
-
-void VrStateCallbacks::onVrStateChanged(bool enabled) {
-    mFlinger.mEnterVrMode = enabled;
-    mFlinger.signalTransaction();
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/VrStateCallbacks.h b/services/surfaceflinger/VrStateCallbacks.h
deleted file mode 100644
index 4e655d3..0000000
--- a/services/surfaceflinger/VrStateCallbacks.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_VR_STATE_CALLBACKS_H
-#define ANDROID_VR_STATE_CALLBACKS_H
-
-#include <vr/vr_manager/vr_manager.h>
-
-namespace android {
-
-class SurfaceFlinger;
-
-class VrStateCallbacks : public BnVrStateCallbacks {
-public:
-    VrStateCallbacks(SurfaceFlinger& flinger);
-    void onVrStateChanged(bool enabled) override;
-
-private:
-    SurfaceFlinger& mFlinger;
-};
-
-} // namespace android
-
-#endif // ANDROID_VR_STATE_CALLBACKS_H
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index eb9f407..3dfd9f1 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -25,7 +25,7 @@
   sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
       defaultServiceManager()->getService(String16("vrmanager")));
   if (vrManagerService.get()) {
-    vrManagerService->unregisterListener(vr_mode_listener_);
+    vrManagerService->unregisterPersistentVrStateListener(vr_mode_listener_);
   }
 }
 
@@ -39,7 +39,7 @@
   sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
       defaultServiceManager()->getService(String16("vrmanager")));
   if (vrManagerService.get()) {
-    vrManagerService->registerListener(vr_mode_listener_);
+    vrManagerService->registerPersistentVrStateListener(vr_mode_listener_);
   }
   return 0;
 }
@@ -315,7 +315,7 @@
   wake_up_init_and_render_.notify_one();
 }
 
-void Application::VrModeListener::onVrStateChanged(bool enabled) {
+void Application::VrModeListener::onPersistentVrStateChanged(bool enabled) {
   if (!enabled)
     app_->QueueTask(MainThreadTask::ExitingVrMode);
 }
diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h
index 6215561..4b36ecc 100644
--- a/services/vr/vr_window_manager/application.h
+++ b/services/vr/vr_window_manager/application.h
@@ -44,10 +44,10 @@
     Show,
   };
 
-  class VrModeListener : public BnVrStateCallbacks {
+  class VrModeListener : public BnPersistentVrStateCallbacks {
    public:
     VrModeListener(Application *app) : app_(app) {}
-    void onVrStateChanged(bool enabled) override;
+    void onPersistentVrStateChanged(bool enabled) override;
 
    private:
     Application *app_;