Merge changes from topic 'vendorbinder'

* changes:
  Add vndservicemanager.
  Allow ProcessState to use another binder dev node.
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 3153aa5..3ba177e 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -78,7 +78,6 @@
         "/system/bin/audioserver",
         "/system/bin/cameraserver",
         "/system/bin/drmserver",
-        "/system/bin/mediacodec",     // media.codec
         "/system/bin/mediadrmserver",
         "/system/bin/mediaextractor", // media.extractor
         "/system/bin/mediaserver",
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 8750147..51a8682 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -456,6 +456,9 @@
     using namespace ::android::hidl::base::V1_0;
     auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
         for (const auto &info : infos) {
+            if (info.clientPids.size() <= 0) {
+                continue;
+            }
             putEntry(PTSERVICEMANAGER_REG_CLIENT, {
                 .interfaceName =
                         std::string{info.interfaceName.c_str()} + "/" +
diff --git a/data/etc/android.hardware.vr.headtracking-0.mxl b/data/etc/android.hardware.vr.headtracking-0.xml
similarity index 100%
rename from data/etc/android.hardware.vr.headtracking-0.mxl
rename to data/etc/android.hardware.vr.headtracking-0.xml
diff --git a/data/etc/android.hardware.vr.headtracking-1.mxl b/data/etc/android.hardware.vr.headtracking-1.xml
similarity index 100%
rename from data/etc/android.hardware.vr.headtracking-1.mxl
rename to data/etc/android.hardware.vr.headtracking-1.xml
diff --git a/data/etc/android.software.companion_device_setup.xml b/data/etc/android.software.companion_device_setup.xml
new file mode 100644
index 0000000..e60ef88
--- /dev/null
+++ b/data/etc/android.software.companion_device_setup.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<permissions>
+    <feature name="android.software.companion_device_setup" />
+</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 2607d58..b5287ac 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -47,6 +47,7 @@
     <feature name="android.software.input_methods" />
     <feature name="android.software.picture_in_picture" />
     <feature name="android.software.print" />
+    <feature name="android.software.companion_device_setup" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index f0ca067..51ea1ca 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -47,6 +47,7 @@
     <feature name="android.software.input_methods" />
     <feature name="android.software.picture_in_picture" />
     <feature name="android.software.print" />
+    <feature name="android.software.companion_device_setup" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 1853cff..7b826d6 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -115,7 +115,6 @@
                                            void* cookie);
     
     const   sp<ProcessState>    mProcess;
-    const   pid_t               mMyThreadId;
             Vector<BBinder*>    mPendingStrongDerefs;
             Vector<RefBase::weakref_type*> mPendingWeakDerefs;
 
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index cbb4491..92251ed 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -43,7 +43,6 @@
     LAST_REFRESH_START,
     GPU_COMPOSITION_DONE,
     DISPLAY_PRESENT,
-    DISPLAY_RETIRE,
     DEQUEUE_READY,
     RELEASE,
     EVENT_COUNT, // Not an actual event.
@@ -70,7 +69,6 @@
     bool hasAcquireInfo() const;
     bool hasGpuCompositionDoneInfo() const;
     bool hasDisplayPresentInfo() const;
-    bool hasDisplayRetireInfo() const;
     bool hasReleaseInfo() const;
     bool hasDequeueReadyInfo() const;
 
@@ -85,7 +83,6 @@
     // encountered help us determine if timestamps aren't available because
     // a) we'll just never get them or b) they're not ready yet.
     bool addPostCompositeCalled{false};
-    bool addRetireCalled{false};
     bool addReleaseCalled{false};
 
     nsecs_t postedTime{TIMESTAMP_PENDING};
@@ -98,7 +95,6 @@
     std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE};
     std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
     std::shared_ptr<FenceTime> displayPresentFence{FenceTime::NO_FENCE};
-    std::shared_ptr<FenceTime> displayRetireFence{FenceTime::NO_FENCE};
     std::shared_ptr<FenceTime> releaseFence{FenceTime::NO_FENCE};
 };
 
@@ -167,7 +163,6 @@
     FenceTimeline mAcquireTimeline;
     FenceTimeline mGpuCompositionDoneTimeline;
     FenceTimeline mPresentTimeline;
-    FenceTimeline mRetireTimeline;
     FenceTimeline mReleaseTimeline;
 };
 
@@ -224,8 +219,6 @@
             const std::shared_ptr<FenceTime>& gpuCompositionDone,
             const std::shared_ptr<FenceTime>& displayPresent,
             const CompositorTiming& compositorTiming);
-    void addRetire(uint64_t frameNumber,
-            const std::shared_ptr<FenceTime>& displayRetire);
     void addRelease(uint64_t frameNumber, nsecs_t dequeueReadyTime,
             std::shared_ptr<FenceTime>&& release);
 
@@ -239,7 +232,6 @@
 
     size_t mQueueOffset{0};
     size_t mCompositionOffset{0};
-    size_t mRetireOffset{0};
     size_t mReleaseOffset{0};
 
     int mCurrentConnectId{0};
@@ -281,7 +273,6 @@
     uint64_t mFrameNumber{0};
 
     bool mAddPostCompositeCalled{0};
-    bool mAddRetireCalled{0};
     bool mAddReleaseCalled{0};
 
     nsecs_t mPostedTime{FrameEvents::TIMESTAMP_PENDING};
@@ -293,17 +284,16 @@
 
     FenceTime::Snapshot mGpuCompositionDoneFence;
     FenceTime::Snapshot mDisplayPresentFence;
-    FenceTime::Snapshot mDisplayRetireFence;
     FenceTime::Snapshot mReleaseFence;
 
     // This is a static method with an auto return value so we can call
     // it without needing const and non-const versions.
     template <typename ThisT>
     static inline auto allFences(ThisT fed) ->
-            std::array<decltype(&fed->mReleaseFence), 4> {
+            std::array<decltype(&fed->mReleaseFence), 3> {
         return {{
             &fed->mGpuCompositionDoneFence, &fed->mDisplayPresentFence,
-            &fed->mDisplayRetireFence, &fed->mReleaseFence
+            &fed->mReleaseFence
         }};
     }
 };
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 9870ba0..2fbe07a 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -126,11 +126,6 @@
     virtual bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& surface) const = 0;
 
-    /* Returns the frame timestamps supported by SurfaceFlinger.
-     */
-    virtual status_t getSupportedFrameTimestamps(
-            std::vector<FrameEvent>* outSupported) const = 0;
-
     /* set display power mode. depending on the mode, it can either trigger
      * screen on, off or low power mode and wait for it to complete.
      * requires ACCESS_SURFACE_FLINGER permission.
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index cfc68c6..62f6cad 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -152,8 +152,8 @@
             nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
             nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
             nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
-            nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
-            nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime);
+            nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
+            nsecs_t* outReleaseTime);
 
     status_t getWideColorSupport(bool* supported);
     status_t getHdrSupport(bool* supported);
@@ -411,11 +411,6 @@
     uint64_t mNextFrameNumber = 1;
     uint64_t mLastFrameNumber = 0;
 
-    // Mutable because ANativeWindow::query needs this class const.
-    mutable bool mQueriedSupportedTimestamps;
-    mutable bool mFrameTimestampsSupportsPresent;
-    mutable bool mFrameTimestampsSupportsRetire;
-
     // A cached copy of the FrameEventHistory maintained by the consumer.
     bool mEnableFrameTimestamps = false;
     std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
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/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 02b4232..d0cd8f2 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -46,6 +46,7 @@
 #define IF_LOG_COMMANDS() if (false)
 #define LOG_REMOTEREFS(...) 
 #define IF_LOG_REMOTEREFS() if (false)
+
 #define LOG_THREADPOOL(...) 
 #define LOG_ONEWAY(...) 
 
@@ -149,7 +150,7 @@
         return cmd;
     }
     out << kReturnStrings[cmdIndex];
-    
+
     switch (code) {
         case BR_TRANSACTION:
         case BR_REPLY: {
@@ -157,12 +158,12 @@
             cmd = (const int32_t *)printBinderTransactionData(out, cmd);
             out << dedent;
         } break;
-        
+
         case BR_ACQUIRE_RESULT: {
             const int32_t res = *cmd++;
             out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
         } break;
-        
+
         case BR_INCREFS:
         case BR_ACQUIRE:
         case BR_RELEASE:
@@ -171,7 +172,7 @@
             const int32_t c = *cmd++;
             out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")";
         } break;
-    
+
         case BR_ATTEMPT_ACQUIRE: {
             const int32_t p = *cmd++;
             const int32_t b = *cmd++;
@@ -191,7 +192,7 @@
             // BR_TRANSACTION_COMPLETE, BR_FINISHED
             break;
     }
-    
+
     out << endl;
     return cmd;
 }
@@ -216,17 +217,17 @@
             cmd = (const int32_t *)printBinderTransactionData(out, cmd);
             out << dedent;
         } break;
-        
+
         case BC_ACQUIRE_RESULT: {
             const int32_t res = *cmd++;
             out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
         } break;
-        
+
         case BC_FREE_BUFFER: {
             const int32_t buf = *cmd++;
             out << ": buffer=" << (void*)(long)buf;
         } break;
-        
+
         case BC_INCREFS:
         case BC_ACQUIRE:
         case BC_RELEASE:
@@ -234,20 +235,20 @@
             const int32_t d = *cmd++;
             out << ": desc=" << d;
         } break;
-    
+
         case BC_INCREFS_DONE:
         case BC_ACQUIRE_DONE: {
             const int32_t b = *cmd++;
             const int32_t c = *cmd++;
             out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")";
         } break;
-        
+
         case BC_ATTEMPT_ACQUIRE: {
             const int32_t p = *cmd++;
             const int32_t d = *cmd++;
             out << ": desc=" << d << ", pri=" << p;
         } break;
-        
+
         case BC_REQUEST_DEATH_NOTIFICATION:
         case BC_CLEAR_DEATH_NOTIFICATION: {
             const int32_t h = *cmd++;
@@ -265,7 +266,7 @@
             // BC_EXIT_LOOPER
             break;
     }
-    
+
     out << endl;
     return cmd;
 }
@@ -285,12 +286,12 @@
         if (st) return st;
         return new IPCThreadState;
     }
-    
+
     if (gShutdown) {
         ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n");
         return NULL;
     }
-    
+
     pthread_mutex_lock(&gTLSMutex);
     if (!gHaveTLS) {
         int key_create_value = pthread_key_create(&gTLS, threadDestructor);
@@ -319,7 +320,7 @@
 void IPCThreadState::shutdown()
 {
     gShutdown = true;
-    
+
     if (gHaveTLS) {
         // XXX Need to wait for all thread pool threads to exit!
         IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
@@ -455,15 +456,6 @@
         }
         pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
         pthread_mutex_unlock(&mProcess->mThreadCountLock);
-
-        // After executing the command, ensure that the thread is returned to the
-        // foreground cgroup before rejoining the pool.  The driver takes care of
-        // restoring the priority, but doesn't do anything with cgroups so we
-        // need to take care of that here in userspace.  Note that we do make
-        // sure to go in the foreground after executing a transaction, but
-        // there are other callbacks into user code that could have changed
-        // our group so we want to make absolutely sure it is put back.
-        set_sched_policy(mMyThreadId, SP_FOREGROUND);
     }
 
     return result;
@@ -498,12 +490,7 @@
     LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
 
     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
-    
-    // This thread may have been spawned by a thread that was in the background
-    // scheduling group, so first we will make sure it is in the foreground
-    // one to avoid performing an initial transaction in the background.
-    set_sched_policy(mMyThreadId, SP_FOREGROUND);
-        
+
     status_t result;
     do {
         processPendingDerefs();
@@ -515,7 +502,7 @@
                   mProcess->mDriverFD, result);
             abort();
         }
-        
+
         // Let this thread exit the thread pool if it is no longer
         // needed and it is not the main process thread.
         if(result == TIMED_OUT && !isMain) {
@@ -525,7 +512,7 @@
 
     LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
         (void*)pthread_self(), getpid(), result);
-    
+
     mOut.writeInt32(BC_EXIT_LOOPER);
     talkWithDriver(false);
 }
@@ -578,18 +565,18 @@
             << handle << " / code " << TypeCode(code) << ": "
             << indent << data << dedent << endl;
     }
-    
+
     if (err == NO_ERROR) {
         LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
             (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
         err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
     }
-    
+
     if (err != NO_ERROR) {
         if (reply) reply->setError(err);
         return (mLastError = err);
     }
-    
+
     if ((flags & TF_ONE_WAY) == 0) {
         #if 0
         if (code == 4) { // relayout
@@ -611,7 +598,7 @@
             ALOGI("<<<<<< RETURNING transaction %d", code);
         }
         #endif
-        
+
         IF_LOG_TRANSACTIONS() {
             TextOutput::Bundle _b(alog);
             alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
@@ -622,7 +609,7 @@
     } else {
         err = waitForResponse(NULL, NULL);
     }
-    
+
     return err;
 }
 
@@ -662,14 +649,14 @@
     mOut.writeInt32(0); // xxx was thread priority
     mOut.writeInt32(handle);
     status_t result = UNKNOWN_ERROR;
-    
+
     waitForResponse(NULL, &result);
-    
+
 #if LOG_REFCOUNTS
     ALOGV("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
         handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
 #endif
-    
+
     return result;
 #else
     (void)handle;
@@ -704,7 +691,6 @@
 
 IPCThreadState::IPCThreadState()
     : mProcess(ProcessState::self()),
-      mMyThreadId(gettid()),
       mStrictModePolicy(0),
       mLastTransactionBinderFlags(0)
 {
@@ -724,7 +710,7 @@
     status_t statusBuffer;
     err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
     if (err < NO_ERROR) return err;
-    
+
     return waitForResponse(NULL, NULL);
 }
 
@@ -738,9 +724,9 @@
         err = mIn.errorCheck();
         if (err < NO_ERROR) break;
         if (mIn.dataAvail() == 0) continue;
-        
+
         cmd = (uint32_t)mIn.readInt32();
-        
+
         IF_LOG_COMMANDS() {
             alog << "Processing waitForResponse Command: "
                 << getReturnString(cmd) << endl;
@@ -750,7 +736,7 @@
         case BR_TRANSACTION_COMPLETE:
             if (!reply && !acquireResult) goto finish;
             break;
-        
+
         case BR_DEAD_REPLY:
             err = DEAD_OBJECT;
             goto finish;
@@ -758,7 +744,7 @@
         case BR_FAILED_REPLY:
             err = FAILED_TRANSACTION;
             goto finish;
-        
+
         case BR_ACQUIRE_RESULT:
             {
                 ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
@@ -767,7 +753,7 @@
                 *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
             }
             goto finish;
-        
+
         case BR_REPLY:
             {
                 binder_transaction_data tr;
@@ -815,7 +801,7 @@
         if (reply) reply->setError(err);
         mLastError = err;
     }
-    
+
     return err;
 }
 
@@ -824,17 +810,17 @@
     if (mProcess->mDriverFD <= 0) {
         return -EBADF;
     }
-    
+
     binder_write_read bwr;
-    
+
     // Is the read buffer empty?
     const bool needRead = mIn.dataPosition() >= mIn.dataSize();
-    
+
     // We don't want to write anything if we are still reading
     // from data left in the input buffer and the caller
     // has requested to read the next data.
     const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
-    
+
     bwr.write_size = outAvail;
     bwr.write_buffer = (uintptr_t)mOut.data();
 
@@ -860,7 +846,7 @@
         alog << "Size of receive buffer: " << bwr.read_size
             << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
     }
-    
+
     // Return immediately if there is nothing to do.
     if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
 
@@ -916,7 +902,7 @@
         }
         return NO_ERROR;
     }
-    
+
     return err;
 }
 
@@ -932,7 +918,7 @@
     tr.cookie = 0;
     tr.sender_pid = 0;
     tr.sender_euid = 0;
-    
+
     const status_t err = data.errorCheck();
     if (err == NO_ERROR) {
         tr.data_size = data.ipcDataSize();
@@ -949,10 +935,10 @@
     } else {
         return (mLastError = err);
     }
-    
+
     mOut.writeInt32(cmd);
     mOut.write(&tr, sizeof(tr));
-    
+
     return NO_ERROR;
 }
 
@@ -968,15 +954,15 @@
     BBinder* obj;
     RefBase::weakref_type* refs;
     status_t result = NO_ERROR;
-    
+
     switch ((uint32_t)cmd) {
     case BR_ERROR:
         result = mIn.readInt32();
         break;
-        
+
     case BR_OK:
         break;
-        
+
     case BR_ACQUIRE:
         refs = (RefBase::weakref_type*)mIn.readPointer();
         obj = (BBinder*)mIn.readPointer();
@@ -992,7 +978,7 @@
         mOut.writePointer((uintptr_t)refs);
         mOut.writePointer((uintptr_t)obj);
         break;
-        
+
     case BR_RELEASE:
         refs = (RefBase::weakref_type*)mIn.readPointer();
         obj = (BBinder*)mIn.readPointer();
@@ -1005,7 +991,7 @@
         }
         mPendingStrongDerefs.push(obj);
         break;
-        
+
     case BR_INCREFS:
         refs = (RefBase::weakref_type*)mIn.readPointer();
         obj = (BBinder*)mIn.readPointer();
@@ -1014,7 +1000,7 @@
         mOut.writePointer((uintptr_t)refs);
         mOut.writePointer((uintptr_t)obj);
         break;
-        
+
     case BR_DECREFS:
         refs = (RefBase::weakref_type*)mIn.readPointer();
         obj = (BBinder*)mIn.readPointer();
@@ -1026,22 +1012,22 @@
         //           refs, obj, refs->refBase());
         mPendingWeakDerefs.push(refs);
         break;
-        
+
     case BR_ATTEMPT_ACQUIRE:
         refs = (RefBase::weakref_type*)mIn.readPointer();
         obj = (BBinder*)mIn.readPointer();
-         
+
         {
             const bool success = refs->attemptIncStrong(mProcess.get());
             ALOG_ASSERT(success && refs->refBase() == obj,
                        "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
                        refs, obj, refs->refBase());
-            
+
             mOut.writeInt32(BC_ACQUIRE_RESULT);
             mOut.writeInt32((int32_t)success);
         }
         break;
-    
+
     case BR_TRANSACTION:
         {
             binder_transaction_data tr;
@@ -1049,14 +1035,14 @@
             ALOG_ASSERT(result == NO_ERROR,
                 "Not enough command data for brTRANSACTION");
             if (result != NO_ERROR) break;
-            
+
             Parcel buffer;
             buffer.ipcSetDataReference(
                 reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                 tr.data_size,
                 reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                 tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
-            
+
             const pid_t origPid = mCallingPid;
             const uid_t origUid = mCallingUid;
             const int32_t origStrictModePolicy = mStrictModePolicy;
@@ -1066,26 +1052,6 @@
             mCallingUid = tr.sender_euid;
             mLastTransactionBinderFlags = tr.flags;
 
-            int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
-            if (gDisableBackgroundScheduling) {
-                if (curPrio > ANDROID_PRIORITY_NORMAL) {
-                    // We have inherited a reduced priority from the caller, but do not
-                    // want to run in that state in this process.  The driver set our
-                    // priority already (though not our scheduling class), so bounce
-                    // it back to the default before invoking the transaction.
-                    setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
-                }
-            } else {
-                if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
-                    // We want to use the inherited priority from the caller.
-                    // Ensure this thread is in the background scheduling class,
-                    // since the driver won't modify scheduling classes for us.
-                    // The scheduling group is reset to default by the caller
-                    // once this method returns after the transaction is complete.
-                    set_sched_policy(mMyThreadId, SP_BACKGROUND);
-                }
-            }
-
             //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
 
             Parcel reply;
@@ -1119,7 +1085,7 @@
 
             //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
             //     mCallingPid, origPid, origUid);
-            
+
             if ((tr.flags & TF_ONE_WAY) == 0) {
                 LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                 if (error < NO_ERROR) reply.setError(error);
@@ -1127,7 +1093,7 @@
             } else {
                 LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
             }
-            
+
             mCallingPid = origPid;
             mCallingUid = origUid;
             mStrictModePolicy = origStrictModePolicy;
@@ -1138,10 +1104,10 @@
                 alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
                     << tr.target.ptr << ": " << indent << reply << dedent << endl;
             }
-            
+
         }
         break;
-    
+
     case BR_DEAD_BINDER:
         {
             BpBinder *proxy = (BpBinder*)mIn.readPointer();
@@ -1149,24 +1115,24 @@
             mOut.writeInt32(BC_DEAD_BINDER_DONE);
             mOut.writePointer((uintptr_t)proxy);
         } break;
-        
+
     case BR_CLEAR_DEATH_NOTIFICATION_DONE:
         {
             BpBinder *proxy = (BpBinder*)mIn.readPointer();
             proxy->getWeakRefs()->decWeak(proxy);
         } break;
-        
+
     case BR_FINISHED:
         result = TIMED_OUT;
         break;
-        
+
     case BR_NOOP:
         break;
-        
+
     case BR_SPAWN_LOOPER:
         mProcess->spawnPooledThread(false);
         break;
-        
+
     default:
         ALOGE("*** BAD COMMAND %d received from Binder driver\n", cmd);
         result = UNKNOWN_ERROR;
@@ -1176,7 +1142,7 @@
     if (result != NO_ERROR) {
         mLastError = result;
     }
-    
+
     return result;
 }
 
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index 019a11e..fccca97 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -52,9 +52,8 @@
 
 bool FrameEvents::hasLastRefreshStartInfo() const {
     // The last refresh start time may continue to update until a new frame
-    // is latched. We know we have the final value once the release or retire
-    // info is set. See ConsumerFrameEventHistory::addRetire/Release.
-    return addRetireCalled || addReleaseCalled;
+    // is latched. We know we have the final value once the release info is set.
+    return addReleaseCalled;
 }
 
 bool FrameEvents::hasDequeueReadyInfo() const {
@@ -76,11 +75,6 @@
     return addPostCompositeCalled;
 }
 
-bool FrameEvents::hasDisplayRetireInfo() const {
-    // We may not get a displayRetire in addRetire for HWC2.
-    return addRetireCalled;
-}
-
 bool FrameEvents::hasReleaseInfo() const {
     return addReleaseCalled;
 }
@@ -89,7 +83,6 @@
     acquireFence->getSignalTime();
     gpuCompositionDoneFence->getSignalTime();
     displayPresentFence->getSignalTime();
-    displayRetireFence->getSignalTime();
     releaseFence->getSignalTime();
 }
 
@@ -145,8 +138,6 @@
             !addPostCompositeCalled, *gpuCompositionDoneFence);
     dumpFenceTime(outString, "Display Present   \t",
             !addPostCompositeCalled, *displayPresentFence);
-    dumpFenceTime(outString, "Display Retire    \t",
-            !addRetireCalled, *displayRetireFence);
 
     outString.appendFormat("--- DequeueReady  \t");
     if (FrameEvents::isValidTimestamp(dequeueReadyTime)) {
@@ -286,7 +277,6 @@
         FrameEvents& frame = mFrames[d.mIndex];
 
         frame.addPostCompositeCalled = d.mAddPostCompositeCalled != 0;
-        frame.addRetireCalled = d.mAddRetireCalled != 0;
         frame.addReleaseCalled = d.mAddReleaseCalled != 0;
 
         frame.postedTime = d.mPostedTime;
@@ -302,7 +292,6 @@
             frame.acquireFence = FenceTime::NO_FENCE;
             frame.gpuCompositionDoneFence = FenceTime::NO_FENCE;
             frame.displayPresentFence = FenceTime::NO_FENCE;
-            frame.displayRetireFence = FenceTime::NO_FENCE;
             frame.releaseFence = FenceTime::NO_FENCE;
             // The consumer only sends valid frames.
             frame.valid = true;
@@ -312,8 +301,6 @@
                 &frame.gpuCompositionDoneFence, d.mGpuCompositionDoneFence);
         applyFenceDelta(&mPresentTimeline,
                 &frame.displayPresentFence, d.mDisplayPresentFence);
-        applyFenceDelta(&mRetireTimeline,
-                &frame.displayRetireFence, d.mDisplayRetireFence);
         applyFenceDelta(&mReleaseTimeline,
                 &frame.releaseFence, d.mReleaseFence);
     }
@@ -323,7 +310,6 @@
     mAcquireTimeline.updateSignalTimes();
     mGpuCompositionDoneTimeline.updateSignalTimes();
     mPresentTimeline.updateSignalTimes();
-    mRetireTimeline.updateSignalTimes();
     mReleaseTimeline.updateSignalTimes();
 }
 
@@ -444,18 +430,6 @@
     }
 }
 
-void ConsumerFrameEventHistory::addRetire(
-        uint64_t frameNumber, const std::shared_ptr<FenceTime>& displayRetire) {
-    FrameEvents* frame = getFrame(frameNumber, &mRetireOffset);
-    if (frame == nullptr) {
-        ALOGE_IF(mProducerWantsEvents, "addRetire: Did not find frame.");
-        return;
-    }
-    frame->addRetireCalled = true;
-    frame->displayRetireFence = displayRetire;
-    mFramesDirty[mRetireOffset].setDirty<FrameEvent::DISPLAY_RETIRE>();
-}
-
 void ConsumerFrameEventHistory::addRelease(uint64_t frameNumber,
         nsecs_t dequeueReadyTime, std::shared_ptr<FenceTime>&& release) {
     FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset);
@@ -515,7 +489,6 @@
     : mIndex(index),
       mFrameNumber(frameTimestamps.frameNumber),
       mAddPostCompositeCalled(frameTimestamps.addPostCompositeCalled),
-      mAddRetireCalled(frameTimestamps.addRetireCalled),
       mAddReleaseCalled(frameTimestamps.addReleaseCalled),
       mPostedTime(frameTimestamps.postedTime),
       mRequestedPresentTime(frameTimestamps.requestedPresentTime),
@@ -531,9 +504,6 @@
         mDisplayPresentFence =
                 frameTimestamps.displayPresentFence->getSnapshot();
     }
-    if (dirtyFields.isDirty<FrameEvent::DISPLAY_RETIRE>()) {
-        mDisplayRetireFence = frameTimestamps.displayRetireFence->getSnapshot();
-    }
     if (dirtyFields.isDirty<FrameEvent::RELEASE>()) {
         mReleaseFence = frameTimestamps.releaseFence->getSnapshot();
     }
@@ -541,9 +511,8 @@
 
 constexpr size_t FrameEventsDelta::minFlattenedSize() {
     return sizeof(FrameEventsDelta::mFrameNumber) +
-            sizeof(uint8_t) + // mIndex
+            sizeof(uint16_t) + // mIndex
             sizeof(uint8_t) + // mAddPostCompositeCalled
-            sizeof(uint8_t) + // mAddRetireCalled
             sizeof(uint8_t) + // mAddReleaseCalled
             sizeof(FrameEventsDelta::mPostedTime) +
             sizeof(FrameEventsDelta::mRequestedPresentTime) +
@@ -578,19 +547,17 @@
     }
 
     if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY ||
-            mIndex > std::numeric_limits<uint8_t>::max()) {
+            mIndex > std::numeric_limits<uint16_t>::max()) {
         return BAD_VALUE;
     }
 
     FlattenableUtils::write(buffer, size, mFrameNumber);
 
-    // These are static_cast to uint8_t for alignment.
-    FlattenableUtils::write(buffer, size, static_cast<uint8_t>(mIndex));
+    // These are static_cast to uint16_t/uint8_t for alignment.
+    FlattenableUtils::write(buffer, size, static_cast<uint16_t>(mIndex));
     FlattenableUtils::write(
             buffer, size, static_cast<uint8_t>(mAddPostCompositeCalled));
     FlattenableUtils::write(
-            buffer, size, static_cast<uint8_t>(mAddRetireCalled));
-    FlattenableUtils::write(
             buffer, size, static_cast<uint8_t>(mAddReleaseCalled));
 
     FlattenableUtils::write(buffer, size, mPostedTime);
@@ -618,19 +585,18 @@
 
     FlattenableUtils::read(buffer, size, mFrameNumber);
 
-    // These were written as uint8_t for alignment.
-    uint8_t temp = 0;
-    FlattenableUtils::read(buffer, size, temp);
-    mIndex = temp;
+    // These were written as uint16_t/uint8_t for alignment.
+    uint16_t temp16 = 0;
+    FlattenableUtils::read(buffer, size, temp16);
+    mIndex = temp16;
     if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY) {
         return BAD_VALUE;
     }
-    FlattenableUtils::read(buffer, size, temp);
-    mAddPostCompositeCalled = static_cast<bool>(temp);
-    FlattenableUtils::read(buffer, size, temp);
-    mAddRetireCalled = static_cast<bool>(temp);
-    FlattenableUtils::read(buffer, size, temp);
-    mAddReleaseCalled = static_cast<bool>(temp);
+    uint8_t temp8 = 0;
+    FlattenableUtils::read(buffer, size, temp8);
+    mAddPostCompositeCalled = static_cast<bool>(temp8);
+    FlattenableUtils::read(buffer, size, temp8);
+    mAddReleaseCalled = static_cast<bool>(temp8);
 
     FlattenableUtils::read(buffer, size, mPostedTime);
     FlattenableUtils::read(buffer, size, mRequestedPresentTime);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 4d2692f..5a32d05 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -166,50 +166,6 @@
         return result != 0;
     }
 
-    virtual status_t getSupportedFrameTimestamps(
-            std::vector<FrameEvent>* outSupported) const {
-        if (!outSupported) {
-            return UNEXPECTED_NULL;
-        }
-        outSupported->clear();
-
-        Parcel data, reply;
-
-        status_t err = data.writeInterfaceToken(
-                ISurfaceComposer::getInterfaceDescriptor());
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        err = remote()->transact(
-                BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS,
-                data, &reply);
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        int32_t result = 0;
-        err = reply.readInt32(&result);
-        if (err != NO_ERROR) {
-            return err;
-        }
-        if (result != NO_ERROR) {
-            return result;
-        }
-
-        std::vector<int32_t> supported;
-        err = reply.readInt32Vector(&supported);
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        outSupported->reserve(supported.size());
-        for (int32_t s : supported) {
-            outSupported->push_back(static_cast<FrameEvent>(s));
-        }
-        return NO_ERROR;
-    }
-
     virtual sp<IDisplayEventConnection> createDisplayEventConnection()
     {
         Parcel data, reply;
@@ -580,25 +536,6 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-        case GET_SUPPORTED_FRAME_TIMESTAMPS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            std::vector<FrameEvent> supportedTimestamps;
-            status_t result = getSupportedFrameTimestamps(&supportedTimestamps);
-            status_t err = reply->writeInt32(result);
-            if (err != NO_ERROR) {
-                return err;
-            }
-            if (result != NO_ERROR) {
-                return result;
-            }
-
-            std::vector<int32_t> supported;
-            supported.reserve(supportedTimestamps.size());
-            for (FrameEvent s : supportedTimestamps) {
-                supported.push_back(static_cast<int32_t>(s));
-            }
-            return reply->writeInt32Vector(supported);
-        }
         case CREATE_DISPLAY_EVENT_CONNECTION: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IDisplayEventConnection> connection(createDisplayEventConnection());
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index a2e12f7..429e837 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -49,9 +49,6 @@
       mAutoRefresh(false),
       mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
       mSharedBufferHasBeenQueued(false),
-      mQueriedSupportedTimestamps(false),
-      mFrameTimestampsSupportsPresent(false),
-      mFrameTimestampsSupportsRetire(false),
       mEnableFrameTimestamps(false),
       mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>())
 {
@@ -199,7 +196,6 @@
         const nsecs_t* outLastRefreshStartTime,
         const nsecs_t* outGpuCompositionDoneTime,
         const nsecs_t* outDisplayPresentTime,
-        const nsecs_t* outDisplayRetireTime,
         const nsecs_t* outDequeueReadyTime,
         const nsecs_t* outReleaseTime) {
     bool checkForLatch = (outLatchTime != nullptr) && !e->hasLatchInfo();
@@ -210,13 +206,11 @@
     bool checkForDisplayPresent = (outDisplayPresentTime != nullptr) &&
             !e->hasDisplayPresentInfo();
 
-    // LastRefreshStart, DisplayRetire, DequeueReady, and Release are never
+    // LastRefreshStart, DequeueReady, and Release are never
     // available for the last frame.
     bool checkForLastRefreshStart = (outLastRefreshStartTime != nullptr) &&
             !e->hasLastRefreshStartInfo() &&
             (e->frameNumber != lastFrameNumber);
-    bool checkForDisplayRetire = (outDisplayRetireTime != nullptr) &&
-            !e->hasDisplayRetireInfo() && (e->frameNumber != lastFrameNumber);
     bool checkForDequeueReady = (outDequeueReadyTime != nullptr) &&
             !e->hasDequeueReadyInfo() && (e->frameNumber != lastFrameNumber);
     bool checkForRelease = (outReleaseTime != nullptr) &&
@@ -225,8 +219,7 @@
     // RequestedPresent and Acquire info are always available producer-side.
     return checkForLatch || checkForFirstRefreshStart ||
             checkForLastRefreshStart || checkForGpuCompositionDone ||
-            checkForDisplayPresent || checkForDisplayRetire ||
-            checkForDequeueReady || checkForRelease;
+            checkForDisplayPresent || checkForDequeueReady || checkForRelease;
 }
 
 static void getFrameTimestamp(nsecs_t *dst, const nsecs_t& src) {
@@ -246,8 +239,8 @@
         nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
         nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
         nsecs_t* outLastRefreshStartTime, nsecs_t* outGpuCompositionDoneTime,
-        nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
-        nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime) {
+        nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
+        nsecs_t* outReleaseTime) {
     ATRACE_CALL();
 
     Mutex::Autolock lock(mMutex);
@@ -256,15 +249,6 @@
         return INVALID_OPERATION;
     }
 
-    // Verify the requested timestamps are supported.
-    querySupportedTimestampsLocked();
-    if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) {
-        return BAD_VALUE;
-    }
-    if (outDisplayRetireTime != nullptr && !mFrameTimestampsSupportsRetire) {
-        return BAD_VALUE;
-    }
-
     FrameEvents* events = mFrameEventHistory->getFrame(frameNumber);
     if (events == nullptr) {
         // If the entry isn't available in the producer, it's definitely not
@@ -276,7 +260,7 @@
     if (checkConsumerForUpdates(events, mLastFrameNumber,
             outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime,
             outGpuCompositionDoneTime, outDisplayPresentTime,
-            outDisplayRetireTime, outDequeueReadyTime, outReleaseTime)) {
+            outDequeueReadyTime, outReleaseTime)) {
         FrameEventHistoryDelta delta;
         mGraphicBufferProducer->getFrameTimestamps(&delta);
         mFrameEventHistory->applyDelta(delta);
@@ -300,7 +284,6 @@
             outGpuCompositionDoneTime, events->gpuCompositionDoneFence);
     getFrameTimestampFence(
             outDisplayPresentTime, events->displayPresentFence);
-    getFrameTimestampFence(outDisplayRetireTime, events->displayRetireFence);
     getFrameTimestampFence(outReleaseTime, events->releaseFence);
 
     return NO_ERROR;
@@ -740,31 +723,6 @@
     return err;
 }
 
-void Surface::querySupportedTimestampsLocked() const {
-    // mMutex must be locked when calling this method.
-
-    if (mQueriedSupportedTimestamps) {
-        return;
-    }
-    mQueriedSupportedTimestamps = true;
-
-    std::vector<FrameEvent> supportedFrameTimestamps;
-    status_t err = composerService()->getSupportedFrameTimestamps(
-            &supportedFrameTimestamps);
-
-    if (err != NO_ERROR) {
-        return;
-    }
-
-    for (auto sft : supportedFrameTimestamps) {
-        if (sft == FrameEvent::DISPLAY_PRESENT) {
-            mFrameTimestampsSupportsPresent = true;
-        } else if (sft == FrameEvent::DISPLAY_RETIRE) {
-            mFrameTimestampsSupportsRetire = true;
-        }
-    }
-}
-
 int Surface::query(int what, int* value) const {
     ATRACE_CALL();
     ALOGV("Surface::query");
@@ -826,16 +784,6 @@
                         static_cast<int>(durationUs);
                 return NO_ERROR;
             }
-            case NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT: {
-                querySupportedTimestampsLocked();
-                *value = mFrameTimestampsSupportsPresent ? 1 : 0;
-                return NO_ERROR;
-            }
-            case NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE: {
-                querySupportedTimestampsLocked();
-                *value = mFrameTimestampsSupportsRetire ? 1 : 0;
-                return NO_ERROR;
-            }
             case NATIVE_WINDOW_IS_VALID: {
                 *value = mGraphicBufferProducer != nullptr ? 1 : 0;
                 return NO_ERROR;
@@ -1090,14 +1038,13 @@
     nsecs_t* outLastRefreshStartTime = va_arg(args, int64_t*);
     nsecs_t* outGpuCompositionDoneTime = va_arg(args, int64_t*);
     nsecs_t* outDisplayPresentTime = va_arg(args, int64_t*);
-    nsecs_t* outDisplayRetireTime = va_arg(args, int64_t*);
     nsecs_t* outDequeueReadyTime = va_arg(args, int64_t*);
     nsecs_t* outReleaseTime = va_arg(args, int64_t*);
     return getFrameTimestamps(frameId,
             outRequestedPresentTime, outAcquireTime, outLatchTime,
             outFirstRefreshStartTime, outLastRefreshStartTime,
             outGpuCompositionDoneTime, outDisplayPresentTime,
-            outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
+            outDequeueReadyTime, outReleaseTime);
 }
 
 int Surface::dispatchGetWideColorSupport(va_list args) {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 58227e6..3932b92 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -358,11 +358,6 @@
 public:
     ~FakeSurfaceComposer() override {}
 
-    void setSupportedTimestamps(bool supportsPresent, bool supportsRetire) {
-        mSupportsPresent = supportsPresent;
-        mSupportsRetire = supportsRetire;
-    }
-
     sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
     sp<ISurfaceComposerClient> createScopedConnection(
             const sp<IGraphicBufferProducer>& /* parent */) override {
@@ -386,30 +381,6 @@
             const sp<IGraphicBufferProducer>& /*surface*/) const override {
         return false;
     }
-
-    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported)
-            const override {
-        *outSupported = {
-                FrameEvent::REQUESTED_PRESENT,
-                FrameEvent::ACQUIRE,
-                FrameEvent::LATCH,
-                FrameEvent::FIRST_REFRESH_START,
-                FrameEvent::LAST_REFRESH_START,
-                FrameEvent::GPU_COMPOSITION_DONE,
-                FrameEvent::DEQUEUE_READY,
-                FrameEvent::RELEASE
-        };
-        if (mSupportsPresent) {
-            outSupported->push_back(
-                        FrameEvent::DISPLAY_PRESENT);
-        }
-        if (mSupportsRetire) {
-            outSupported->push_back(
-                        FrameEvent::DISPLAY_RETIRE);
-        }
-        return NO_ERROR;
-    }
-
     void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
     status_t getDisplayConfigs(const sp<IBinder>& /*display*/,
             Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
@@ -574,8 +545,7 @@
               kConsumerAcquireTime(frameStartTime + 301),
               kLatchTime(frameStartTime + 500),
               kDequeueReadyTime(frameStartTime + 600),
-              kRetireTime(frameStartTime + 700),
-              kReleaseTime(frameStartTime + 800),
+              kReleaseTime(frameStartTime + 700),
               mRefreshes {
                     { mFenceMap, frameStartTime + 410 },
                     { mFenceMap, frameStartTime + 420 },
@@ -595,7 +565,6 @@
         }
 
         void signalReleaseFences() {
-            mFenceMap.signalAllForTest(mRetire.mFence, kRetireTime);
             mFenceMap.signalAllForTest(mRelease.mFence, kReleaseTime);
         }
 
@@ -603,7 +572,6 @@
 
         FenceAndFenceTime mAcquireConsumer { mFenceMap };
         FenceAndFenceTime mAcquireProducer { mFenceMap };
-        FenceAndFenceTime mRetire { mFenceMap };
         FenceAndFenceTime mRelease { mFenceMap };
 
         const nsecs_t kPostedTime;
@@ -612,7 +580,6 @@
         const nsecs_t kConsumerAcquireTime;
         const nsecs_t kLatchTime;
         const nsecs_t kDequeueReadyTime;
-        const nsecs_t kRetireTime;
         const nsecs_t kReleaseTime;
 
         RefreshEvents mRefreshes[3];
@@ -651,7 +618,7 @@
                 &outRequestedPresentTime, &outAcquireTime, &outLatchTime,
                 &outFirstRefreshStartTime, &outLastRefreshStartTime,
                 &outGpuCompositionDoneTime, &outDisplayPresentTime,
-                &outDisplayRetireTime, &outDequeueReadyTime, &outReleaseTime);
+                &outDequeueReadyTime, &outReleaseTime);
     }
 
     void resetTimestamps() {
@@ -662,7 +629,6 @@
         outLastRefreshStartTime = -1;
         outGpuCompositionDoneTime = -1;
         outDisplayPresentTime = -1;
-        outDisplayRetireTime = -1;
         outDequeueReadyTime = -1;
         outReleaseTime = -1;
     }
@@ -715,8 +681,8 @@
         uint64_t nOldFrame = iOldFrame + 1;
         uint64_t nNewFrame = iNewFrame + 1;
 
-        // Latch, Composite, Retire, and Release the frames in a plausible
-        // order. Note: The timestamps won't necessarily match the order, but
+        // Latch, Composite, and Release the frames in a plausible order.
+        // Note: The timestamps won't necessarily match the order, but
         // that's okay for the purposes of this test.
         std::shared_ptr<FenceTime> gpuDoneFenceTime = FenceTime::NO_FENCE;
 
@@ -750,11 +716,6 @@
                 newFrame->mRefreshes[0].mPresent.mFenceTime,
                 newFrame->mRefreshes[0].kCompositorTiming);
 
-        // Retire the previous buffer just after compositing the new buffer.
-        if (oldFrame != nullptr) {
-            mCfeh->addRetire(nOldFrame, oldFrame->mRetire.mFenceTime);
-        }
-
         mCfeh->addPreComposition(nNewFrame, newFrame->mRefreshes[1].kStartTime);
         gpuDoneFenceTime = gpuComposited ?
                 newFrame->mRefreshes[1].mGpuCompositionDone.mFenceTime :
@@ -764,11 +725,6 @@
                 newFrame->mRefreshes[1].kCompositorTiming);
     }
 
-    void QueryPresentRetireSupported(
-            bool displayPresentSupported, bool displayRetireSupported);
-    void PresentOrRetireUnsupportedNoSyncTest(
-            bool displayPresentSupported, bool displayRetireSupported);
-
     sp<IGraphicBufferProducer> mProducer;
     sp<IGraphicBufferConsumer> mConsumer;
     sp<FakeConsumer> mFakeConsumer;
@@ -787,7 +743,6 @@
     int64_t outLastRefreshStartTime = -1;
     int64_t outGpuCompositionDoneTime = -1;
     int64_t outDisplayPresentTime = -1;
-    int64_t outDisplayRetireTime = -1;
     int64_t outDequeueReadyTime = -1;
     int64_t outReleaseTime = -1;
 
@@ -899,31 +854,6 @@
     EXPECT_EQ(4, mFakeConsumer->mGetFrameTimestampsCount);
 }
 
-void GetFrameTimestampsTest::QueryPresentRetireSupported(
-        bool displayPresentSupported, bool displayRetireSupported) {
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(
-            displayPresentSupported, displayRetireSupported);
-
-    // Verify supported bits are forwarded.
-    int supportsPresent = -1;
-    mWindow.get()->query(mWindow.get(),
-            NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent);
-    EXPECT_EQ(displayPresentSupported, supportsPresent);
-
-    int supportsRetire = -1;
-    mWindow.get()->query(mWindow.get(),
-            NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE, &supportsRetire);
-    EXPECT_EQ(displayRetireSupported, supportsRetire);
-}
-
-TEST_F(GetFrameTimestampsTest, QueryPresentSupported) {
-   QueryPresentRetireSupported(true, false);
-}
-
-TEST_F(GetFrameTimestampsTest, QueryRetireSupported) {
-   QueryPresentRetireSupported(false, true);
-}
-
 TEST_F(GetFrameTimestampsTest, SnapToNextTickBasic) {
     nsecs_t phase = 4000;
     nsecs_t interval = 1000;
@@ -1184,7 +1114,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[0].kGpuCompositionDoneTime,
             outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
-    EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
 
@@ -1200,7 +1129,6 @@
     EXPECT_EQ(mFrames[1].mRefreshes[0].kGpuCompositionDoneTime,
             outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(0, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 }
@@ -1209,7 +1137,6 @@
 // back to the producer and the producer saves its own fence.
 TEST_F(GetFrameTimestampsTest, QueueTimestampsNoSync) {
     enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
 
     // Dequeue and queue frame 1.
     const uint64_t fId1 = getNextFrameId();
@@ -1222,7 +1149,7 @@
     int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     int result = native_window_get_frame_timestamps(mWindow.get(), fId1,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -1234,7 +1161,7 @@
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     result = native_window_get_frame_timestamps(mWindow.get(), fId1,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -1251,7 +1178,7 @@
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     result = native_window_get_frame_timestamps(mWindow.get(), fId2,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
@@ -1263,7 +1190,7 @@
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     result = native_window_get_frame_timestamps(mWindow.get(), fId2,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
@@ -1272,7 +1199,6 @@
 
 TEST_F(GetFrameTimestampsTest, ZeroRequestedTimestampsNoSync) {
     enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
 
     // Dequeue and queue frame 1.
     dequeueAndQueue(0);
@@ -1292,7 +1218,7 @@
     // Verify a request for no timestamps doesn't result in a sync call.
     int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     int result = native_window_get_frame_timestamps(mWindow.get(), fId2,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
             nullptr, nullptr, nullptr);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
@@ -1302,7 +1228,6 @@
 // side without an additional sync call to the consumer.
 TEST_F(GetFrameTimestampsTest, FencesInProducerNoSync) {
     enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
 
     // Dequeue and queue frame 1.
     const uint64_t fId1 = getNextFrameId();
@@ -1332,7 +1257,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
@@ -1351,7 +1275,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
@@ -1373,7 +1296,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[0].kGpuCompositionDoneTime,
             outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
-    EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
 }
@@ -1383,7 +1305,6 @@
 // never exist.
 TEST_F(GetFrameTimestampsTest, NoGpuNoSync) {
     enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
 
     // Dequeue and queue frame 1.
     const uint64_t fId1 = getNextFrameId();
@@ -1413,7 +1334,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
@@ -1435,7 +1355,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
-    EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
 }
@@ -1444,7 +1363,6 @@
 // the most recent frame, then a sync call is not done.
 TEST_F(GetFrameTimestampsTest, NoRetireOrReleaseNoSync) {
     enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
 
     // Dequeue and queue frame 1.
     const uint64_t fId1 = getNextFrameId();
@@ -1475,7 +1393,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
@@ -1484,7 +1401,7 @@
     mFrames[1].signalRefreshFences();
 
     // Verify querying for all timestmaps of f2 does not do a sync call. Even
-    // though the lastRefresh, retire, dequeueReady, and release times aren't
+    // though the lastRefresh, dequeueReady, and release times aren't
     // available, a sync call should not occur because it's not possible for f2
     // to encounter the final value for those events until another frame is
     // queued.
@@ -1500,45 +1417,8 @@
     EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(0, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 }
 
-// This test verifies there are no sync calls for present or retire times
-// when they aren't supported and that an error is returned.
-void GetFrameTimestampsTest::PresentOrRetireUnsupportedNoSyncTest(
-        bool displayPresentSupported, bool displayRetireSupported) {
-
-    enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(
-        displayPresentSupported, displayRetireSupported);
-
-    // Dequeue and queue frame 1.
-    const uint64_t fId1 = getNextFrameId();
-    dequeueAndQueue(0);
-
-    // Verify a query for the Present and Retire times do not trigger
-    // a sync call if they are not supported.
-    resetTimestamps();
-    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
-    int result = native_window_get_frame_timestamps(mWindow.get(), fId1,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
-            displayPresentSupported ? nullptr : &outDisplayPresentTime,
-            displayRetireSupported ? nullptr : &outDisplayRetireTime,
-            nullptr, nullptr);
-    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
-    EXPECT_EQ(BAD_VALUE, result);
-    EXPECT_EQ(-1, outDisplayRetireTime);
-    EXPECT_EQ(-1, outDisplayPresentTime);
-}
-
-TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) {
-   PresentOrRetireUnsupportedNoSyncTest(false, true);
-}
-
-TEST_F(GetFrameTimestampsTest, RetireUnsupportedNoSync) {
-   PresentOrRetireUnsupportedNoSyncTest(true, false);
-}
-
 }
diff --git a/libs/hwc2on1adapter/Android.bp b/libs/hwc2on1adapter/Android.bp
index 2be3e67..438d3f5 100644
--- a/libs/hwc2on1adapter/Android.bp
+++ b/libs/hwc2on1adapter/Android.bp
@@ -48,6 +48,9 @@
         "-Wno-sign-conversion",
         "-Wno-switch-enum",
         "-Wno-float-equal",
+        "-Wno-shorten-64-to-32",
+        "-Wno-sign-compare",
+        "-Wno-missing-prototypes",
     ],
 
     srcs: [
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 9309275..d6d3304 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -38,14 +38,15 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-android::Mutex android::SensorManager::sLock;
-std::map<String16, SensorManager*> android::SensorManager::sPackageInstances;
+Mutex SensorManager::sLock;
+std::map<String16, SensorManager*> SensorManager::sPackageInstances;
 
 SensorManager& SensorManager::getInstanceForPackage(const String16& packageName) {
+    waitForSensorService(nullptr);
+
     Mutex::Autolock _l(sLock);
     SensorManager* sensorManager;
-    std::map<String16, SensorManager*>::iterator iterator =
-        sPackageInstances.find(packageName);
+    auto iterator = sPackageInstances.find(packageName);
 
     if (iterator != sPackageInstances.end()) {
         sensorManager = iterator->second;
@@ -100,6 +101,28 @@
     free(mSensorList);
 }
 
+status_t SensorManager::waitForSensorService(sp<ISensorServer> *server) {
+    // try for 300 seconds (60*5(getService() tries for 5 seconds)) before giving up ...
+    sp<ISensorServer> s;
+    const String16 name("sensorservice");
+    for (int i = 0; i < 60; i++) {
+        status_t err = getService(name, &s);
+        switch (err) {
+            case NAME_NOT_FOUND:
+                sleep(1);
+                continue;
+            case NO_ERROR:
+                if (server != nullptr) {
+                    *server = s;
+                }
+                return NO_ERROR;
+            default:
+                return err;
+        }
+    }
+    return TIMED_OUT;
+}
+
 void SensorManager::sensorManagerDied() {
     Mutex::Autolock _l(mLock);
     mSensorServer.clear();
@@ -120,19 +143,8 @@
         }
     }
     if (initSensorManager) {
-        // try for 300 seconds (60*5(getService() tries for 5 seconds)) before giving up ...
-        const String16 name("sensorservice");
-        for (int i = 0; i < 60; i++) {
-            status_t err = getService(name, &mSensorServer);
-            if (err == NAME_NOT_FOUND) {
-                sleep(1);
-                continue;
-            }
-            if (err != NO_ERROR) {
-                return err;
-            }
-            break;
-        }
+        waitForSensorService(&mSensorServer);
+        LOG_ALWAYS_FATAL_IF(mSensorServer == nullptr, "getService(SensorService) NULL");
 
         class DeathObserver : public IBinder::DeathRecipient {
             SensorManager& mSensorManager;
@@ -144,8 +156,6 @@
             explicit DeathObserver(SensorManager& mgr) : mSensorManager(mgr) { }
         };
 
-        LOG_ALWAYS_FATAL_IF(mSensorServer.get() == NULL, "getService(SensorService) NULL");
-
         mDeathObserver = new DeathObserver(*const_cast<SensorManager *>(this));
         IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver);
 
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index a3d9741..92c9823 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -68,6 +68,7 @@
 private:
     // DeathRecipient interface
     void sensorManagerDied();
+    static status_t waitForSensorService(sp<ISensorServer> *server);
 
     SensorManager(const String16& opPackageName);
     status_t assertStateLocked();
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 452bad0..e068469 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -15,6 +15,7 @@
 sourceFiles = [
     "buffer_hub_client.cpp",
     "buffer_hub_rpc.cpp",
+    "dvr_buffer.cpp",
     "ion_buffer.cpp",
 ]
 
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 7268b76..2749fd1 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -130,6 +130,13 @@
   return ret;
 }
 
+void BufferHubBuffer::GetBlobFds(int* fds, size_t* fds_count,
+                                 size_t max_fds_count) const {
+  size_t numFds = static_cast<size_t>(native_handle()->numFds);
+  *fds_count = std::min(max_fds_count, numFds);
+  std::copy(native_handle()->data, native_handle()->data + *fds_count, fds);
+}
+
 BufferConsumer::BufferConsumer(LocalChannelHandle channel)
     : BASE(std::move(channel)) {
   const int ret = ImportBuffer();
diff --git a/libs/vr/libbufferhub/dvr_buffer.cpp b/libs/vr/libbufferhub/dvr_buffer.cpp
new file mode 100644
index 0000000..3eb611f
--- /dev/null
+++ b/libs/vr/libbufferhub/dvr_buffer.cpp
@@ -0,0 +1,124 @@
+#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/dvr_buffer.h>
+#include <ui/GraphicBuffer.h>
+
+using namespace android;
+
+struct DvrWriteBuffer {
+  std::unique_ptr<dvr::BufferProducer> write_buffer_;
+  sp<GraphicBuffer> graphic_buffer_;
+};
+
+struct DvrReadBuffer {
+  std::unique_ptr<dvr::BufferConsumer> read_buffer_;
+  sp<GraphicBuffer> graphic_buffer_;
+};
+
+namespace android {
+namespace dvr {
+
+DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
+    std::unique_ptr<dvr::BufferProducer> buffer_producer) {
+  DvrWriteBuffer* write_buffer = new DvrWriteBuffer;
+  write_buffer->write_buffer_ = std::move(buffer_producer);
+  return write_buffer;
+}
+
+DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer(
+    std::unique_ptr<dvr::BufferConsumer> buffer_consumer) {
+  DvrReadBuffer* read_buffer = new DvrReadBuffer;
+  read_buffer->read_buffer_ = std::move(buffer_consumer);
+  return read_buffer;
+}
+
+}  // namespace dvr
+}  // namespace android
+
+namespace {
+
+void InitializeGraphicBuffer(const dvr::BufferHubBuffer* buffer,
+                             sp<GraphicBuffer>* graphic_buffer) {
+  *graphic_buffer = sp<GraphicBuffer>(new GraphicBuffer(
+      buffer->width(), buffer->height(), buffer->format(), 1, /* layer count */
+      buffer->usage(), buffer->stride(), buffer->native_handle(),
+      false /* keep ownership */));
+}
+
+}  // anonymous namespace
+
+extern "C" {
+
+void dvrWriteBufferDestroy(DvrWriteBuffer* client) { delete client; }
+
+void dvrWriteBufferGetBlobFds(DvrWriteBuffer* client, int* fds,
+                              size_t* fds_count, size_t max_fds_count) {
+  client->write_buffer_->GetBlobFds(fds, fds_count, max_fds_count);
+}
+
+int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* client,
+                                     AHardwareBuffer** hardware_buffer) {
+  if (!client->graphic_buffer_.get()) {
+    InitializeGraphicBuffer(client->write_buffer_.get(),
+                            &client->graphic_buffer_);
+  }
+  *hardware_buffer =
+      reinterpret_cast<AHardwareBuffer*>(client->graphic_buffer_.get());
+  return 0;
+}
+
+int dvrWriteBufferPost(DvrWriteBuffer* client, int ready_fence_fd,
+                       const void* meta, size_t meta_size_bytes) {
+  pdx::LocalHandle fence(ready_fence_fd);
+  int result = client->write_buffer_->Post(fence, meta, meta_size_bytes);
+  fence.Release();
+  return result;
+}
+
+int dvrWriteBufferGain(DvrWriteBuffer* client, int* release_fence_fd) {
+  pdx::LocalHandle release_fence;
+  int result = client->write_buffer_->Gain(&release_fence);
+  *release_fence_fd = release_fence.Release();
+  return result;
+}
+
+int dvrWriteBufferGainAsync(DvrWriteBuffer* client) {
+  return client->write_buffer_->GainAsync();
+}
+
+void dvrReadBufferGetBlobFds(DvrReadBuffer* client, int* fds, size_t* fds_count,
+                             size_t max_fds_count) {
+  client->read_buffer_->GetBlobFds(fds, fds_count, max_fds_count);
+}
+
+int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* client,
+                                    AHardwareBuffer** hardware_buffer) {
+  if (!client->graphic_buffer_.get()) {
+    InitializeGraphicBuffer(client->read_buffer_.get(),
+                            &client->graphic_buffer_);
+  }
+  *hardware_buffer =
+      reinterpret_cast<AHardwareBuffer*>(client->graphic_buffer_.get());
+  return 0;
+}
+
+int dvrReadBufferAcquire(DvrReadBuffer* client, int* ready_fence_fd, void* meta,
+                         size_t meta_size_bytes) {
+  pdx::LocalHandle ready_fence;
+  int result =
+      client->read_buffer_->Acquire(&ready_fence, meta, meta_size_bytes);
+  *ready_fence_fd = ready_fence.Release();
+  return result;
+}
+
+int dvrReadBufferRelease(DvrReadBuffer* client, int release_fence_fd) {
+  pdx::LocalHandle fence(release_fence_fd);
+  int result = client->read_buffer_->Release(fence);
+  fence.Release();
+  return result;
+}
+
+int dvrReadBufferReleaseAsync(DvrReadBuffer* client) {
+  return client->read_buffer_->ReleaseAsync();
+}
+
+}  // extern "C"
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index cefde7b..aacc385 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -70,6 +70,10 @@
     return LocalHandle(dup(native_handle()->data[0]));
   }
 
+  // Get up to |max_fds_count| file descriptors for accessing the blob shared
+  // memory. |fds_count| will contain the actual number of file descriptors.
+  void GetBlobFds(int* fds, size_t* fds_count, size_t max_fds_count) const;
+
   using Client::event_fd;
 
   Status<int> GetEventMask(int events) {
diff --git a/libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h b/libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h
new file mode 100644
index 0000000..c14b1a3
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h
@@ -0,0 +1,55 @@
+#ifndef ANDROID_DVR_BUFFER_H_
+#define ANDROID_DVR_BUFFER_H_
+
+#include <memory>
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DvrWriteBuffer DvrWriteBuffer;
+typedef struct DvrReadBuffer DvrReadBuffer;
+typedef struct AHardwareBuffer AHardwareBuffer;
+
+// Write buffer
+void dvrWriteBufferDestroy(DvrWriteBuffer* client);
+void dvrWriteBufferGetBlobFds(DvrWriteBuffer* client, int* fds,
+                              size_t* fds_count, size_t max_fds_count);
+int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* client,
+                                     AHardwareBuffer** hardware_buffer);
+int dvrWriteBufferPost(DvrWriteBuffer* client, int ready_fence_fd,
+                       const void* meta, size_t meta_size_bytes);
+int dvrWriteBufferGain(DvrWriteBuffer* client, int* release_fence_fd);
+int dvrWriteBufferGainAsync(DvrWriteBuffer* client);
+
+// Read buffer
+void dvrReadBufferGetBlobFds(DvrReadBuffer* client, int* fds, size_t* fds_count,
+                             size_t max_fds_count);
+int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* client,
+                                    AHardwareBuffer** hardware_buffer);
+int dvrReadBufferAcquire(DvrReadBuffer* client, int* ready_fence_fd, void* meta,
+                         size_t meta_size_bytes);
+int dvrReadBufferRelease(DvrReadBuffer* client, int release_fence_fd);
+int dvrReadBufferReleaseAsync(DvrReadBuffer* client);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+namespace android {
+namespace dvr {
+
+class BufferProducer;
+class BufferConsumer;
+
+DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
+    std::unique_ptr<BufferProducer> buffer_producer);
+DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer(
+    std::unique_ptr<BufferConsumer> buffer_consumer);
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFER_H_
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index dcdd994..50d95f7 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -248,33 +248,23 @@
   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);
 }
 
+std::unique_ptr<BufferConsumer> DisplayClient::GetPoseBuffer() {
+  auto status = InvokeRemoteMethod<DisplayRPC::GetPoseBuffer>();
+  if (!status) {
+    ALOGE(
+        "DisplayClient::GetPoseBuffer: Failed to get pose buffer %s",
+        status.GetErrorMessage().c_str());
+    return nullptr;
+  }
+
+  return BufferConsumer::Import(std::move(status));
+}
+
+
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
index fe18619..d60d35b 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdisplay/display_manager_client.cpp
@@ -2,6 +2,7 @@
 
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/display_manager_client_impl.h>
+#include <private/dvr/dvr_buffer.h>
 
 using android::dvr::DisplaySurfaceAttributeEnum;
 
@@ -41,6 +42,18 @@
   delete client;
 }
 
+DvrWriteBuffer* dvrDisplayManagerSetupPoseBuffer(
+    DvrDisplayManagerClient* client, size_t extended_region_size,
+    uint64_t usage0, uint64_t usage1) {
+  // TODO(hendrikw): When we move to gralloc1, pass both usage0 and usage1 down.
+  auto buffer_producer = client->client->SetupPoseBuffer(
+      extended_region_size, static_cast<int>(usage0));
+  if (buffer_producer) {
+    return CreateDvrWriteBufferFromBufferProducer(std::move(buffer_producer));
+  }
+  return nullptr;
+}
+
 int dvrDisplayManagerClientGetEventFd(DvrDisplayManagerClient* client) {
   return client->client->event_fd();
 }
diff --git a/libs/vr/libdisplay/display_manager_client_impl.cpp b/libs/vr/libdisplay/display_manager_client_impl.cpp
index 3fbd1e0..7993fce 100644
--- a/libs/vr/libdisplay/display_manager_client_impl.cpp
+++ b/libs/vr/libdisplay/display_manager_client_impl.cpp
@@ -31,5 +31,20 @@
   return 0;
 }
 
+std::unique_ptr<BufferProducer> DisplayManagerClient::SetupPoseBuffer(
+    size_t extended_region_size, int usage) {
+  auto status = InvokeRemoteMethod<DisplayManagerRPC::SetupPoseBuffer>(
+      extended_region_size, usage);
+  if (!status) {
+    ALOGE(
+        "DisplayManagerClient::SetupPoseBuffer: Failed to create the pose "
+        "buffer %s",
+        status.GetErrorMessage().c_str());
+    return {};
+  }
+
+  return BufferProducer::Import(std::move(status));
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libdisplay/graphics.cpp b/libs/vr/libdisplay/graphics.cpp
index 61f6fea..c2fbb8b 100644
--- a/libs/vr/libdisplay/graphics.cpp
+++ b/libs/vr/libdisplay/graphics.cpp
@@ -17,6 +17,7 @@
 #include <private/dvr/clock_ns.h>
 #include <private/dvr/debug.h>
 #include <private/dvr/display_types.h>
+#include <private/dvr/dvr_buffer.h>
 #include <private/dvr/frame_history.h>
 #include <private/dvr/gl_fenced_flush.h>
 #include <private/dvr/graphics/vr_gl_extensions.h>
@@ -1571,3 +1572,14 @@
     };
   }
 }
+
+extern "C" int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer) {
+  auto client = android::dvr::DisplayClient::Create();
+  if (!client) {
+    ALOGE("Failed to create display client!");
+    return -ECOMM;
+  }
+
+  *pose_buffer = CreateDvrReadBufferFromBufferConsumer(client->GetPoseBuffer());
+  return 0;
+}
diff --git a/libs/vr/libdisplay/include/dvr/graphics.h b/libs/vr/libdisplay/include/dvr/graphics.h
index 19deec3..fc51d52 100644
--- a/libs/vr/libdisplay/include/dvr/graphics.h
+++ b/libs/vr/libdisplay/include/dvr/graphics.h
@@ -160,6 +160,8 @@
 
 int dvrGetNativeDisplayDimensions(int* native_width, int* native_height);
 
+typedef struct DvrReadBuffer DvrReadBuffer;
+
 // Opaque struct that represents a graphics context, the texture swap chain,
 // and surfaces.
 typedef struct DvrGraphicsContext DvrGraphicsContext;
@@ -440,6 +442,9 @@
                                         const int eye,
                                         const float* transform);
 
+// Get a pointer to the global pose buffer.
+int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer);
+
 __END_DECLS
 
 #endif  // DVR_GRAPHICS_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index e1471c3..f579a8c 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -105,12 +105,11 @@
   // 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);
 
+  std::unique_ptr<BufferConsumer> GetPoseBuffer();
+
  private:
   friend BASE;
 
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
index f515b8f..0928d43 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
@@ -14,11 +14,16 @@
     DvrDisplayManagerClientSurfaceList;
 typedef struct DvrDisplayManagerClientSurfaceBuffers
     DvrDisplayManagerClientSurfaceBuffers;
+typedef struct DvrWriteBuffer DvrWriteBuffer;
 
 DvrDisplayManagerClient* dvrDisplayManagerClientCreate();
 
 void dvrDisplayManagerClientDestroy(DvrDisplayManagerClient* client);
 
+DvrWriteBuffer* dvrDisplayManagerSetupPoseBuffer(
+    DvrDisplayManagerClient* client, size_t extended_region_size,
+    uint64_t usage0, uint64_t usage1);
+
 // Return an event fd for checking if there was an event on the server
 // Note that the only event which will be flagged is POLLIN. You must use
 // dvrDisplayManagerClientTranslateEpollEventMask in order to get the real
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
index 0897126..144cd3b 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
@@ -9,7 +9,7 @@
 namespace android {
 namespace dvr {
 
-class BufferConsumer;
+class BufferProducer;
 
 class DisplayManagerClient : public pdx::ClientBase<DisplayManagerClient> {
  public:
@@ -17,6 +17,9 @@
 
   int GetSurfaceList(std::vector<DisplaySurfaceInfo>* surface_list);
 
+  std::unique_ptr<BufferProducer> SetupPoseBuffer(size_t extended_region_size,
+                                                  int usage);
+
   using Client::event_fd;
   using Client::GetChannel;
 
diff --git a/libs/vr/libdisplay/include/private/dvr/display_rpc.h b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
index 465fbae..7a2986a 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
@@ -217,9 +217,8 @@
     kOpGetMetadataBuffer,
     kOpCreateVideoMeshSurface,
     kOpVideoMeshSurfaceCreateProducerQueue,
-    kOpEnterVrMode,
-    kOpExitVrMode,
-    kOpSetViewerParams
+    kOpSetViewerParams,
+    kOpGetPoseBuffer,
   };
 
   // Aliases.
@@ -245,10 +244,10 @@
   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,
+                    LocalChannelHandle(Void));
 };
 
 struct DisplayManagerRPC {
@@ -259,6 +258,7 @@
   enum {
     kOpGetSurfaceList = 0,
     kOpUpdateSurfaces,
+    kOpSetupPoseBuffer,
   };
 
   // Aliases.
@@ -271,6 +271,8 @@
   PDX_REMOTE_METHOD(
       UpdateSurfaces, kOpUpdateSurfaces,
       int(const std::map<int, DisplaySurfaceAttributes>& updates));
+  PDX_REMOTE_METHOD(SetupPoseBuffer, kOpSetupPoseBuffer,
+                    LocalChannelHandle(size_t extended_region_size, int usage));
 };
 
 struct ScreenshotData {
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_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index 6df1642..e07901d 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -82,6 +82,11 @@
           *this, &DisplayManagerService::OnUpdateSurfaces, message);
       return 0;
 
+  case DisplayManagerRPC::SetupPoseBuffer::Opcode:
+      DispatchRemoteMethod<DisplayManagerRPC::SetupPoseBuffer>(
+          *this, &DisplayManagerService::OnSetupPoseBuffer, message);
+      return 0;
+
     default:
       return Service::DefaultHandleMessage(message);
   }
@@ -91,30 +96,31 @@
     pdx::Message& /*message*/) {
   std::vector<DisplaySurfaceInfo> items;
 
-  display_service_->ForEachDisplaySurface([&items](
-      const std::shared_ptr<DisplaySurface>& surface) mutable {
-    DisplaySurfaceInfo item;
+  display_service_->ForEachDisplaySurface(
+      [&items](const std::shared_ptr<DisplaySurface>& surface) mutable {
+        DisplaySurfaceInfo item;
 
-    item.surface_id = surface->surface_id();
-    item.process_id = surface->process_id();
-    item.type = surface->type();
-    item.flags = 0;  // TODO(eieio)
-    item.client_attributes = DisplaySurfaceAttributes{
-        {DisplaySurfaceAttributeEnum::Visible,
-         DisplaySurfaceAttributeValue{surface->client_visible()}},
-        {DisplaySurfaceAttributeEnum::ZOrder,
-         DisplaySurfaceAttributeValue{surface->client_z_order()}},
-        {DisplaySurfaceAttributeEnum::Blur, DisplaySurfaceAttributeValue{0.f}}};
-    item.manager_attributes = DisplaySurfaceAttributes{
-        {DisplaySurfaceAttributeEnum::Visible,
-         DisplaySurfaceAttributeValue{surface->manager_visible()}},
-        {DisplaySurfaceAttributeEnum::ZOrder,
-         DisplaySurfaceAttributeValue{surface->manager_z_order()}},
-        {DisplaySurfaceAttributeEnum::Blur,
-         DisplaySurfaceAttributeValue{surface->manager_blur()}}};
+        item.surface_id = surface->surface_id();
+        item.process_id = surface->process_id();
+        item.type = surface->type();
+        item.flags = 0;  // TODO(eieio)
+        item.client_attributes = DisplaySurfaceAttributes{
+            {DisplaySurfaceAttributeEnum::Visible,
+             DisplaySurfaceAttributeValue{surface->client_visible()}},
+            {DisplaySurfaceAttributeEnum::ZOrder,
+             DisplaySurfaceAttributeValue{surface->client_z_order()}},
+            {DisplaySurfaceAttributeEnum::Blur,
+             DisplaySurfaceAttributeValue{0.f}}};
+        item.manager_attributes = DisplaySurfaceAttributes{
+            {DisplaySurfaceAttributeEnum::Visible,
+             DisplaySurfaceAttributeValue{surface->manager_visible()}},
+            {DisplaySurfaceAttributeEnum::ZOrder,
+             DisplaySurfaceAttributeValue{surface->manager_z_order()}},
+            {DisplaySurfaceAttributeEnum::Blur,
+             DisplaySurfaceAttributeValue{surface->manager_blur()}}};
 
-    items.push_back(item);
-  });
+        items.push_back(item);
+      });
 
   // The fact that we're in the message handler implies that display_manager_ is
   // not nullptr. No check required, unless this service becomes multi-threaded.
@@ -182,6 +188,11 @@
   return 0;
 }
 
+pdx::BorrowedChannelHandle DisplayManagerService::OnSetupPoseBuffer(
+    pdx::Message& message, size_t extended_region_size, int usage) {
+  return display_service_->SetupPoseBuffer(extended_region_size, usage);
+}
+
 void DisplayManagerService::OnDisplaySurfaceChange() {
   if (display_manager_) {
     display_manager_->SetNotificationsPending(true);
diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h
index 3f83c7d..19098c2 100644
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ b/libs/vr/libvrflinger/display_manager_service.h
@@ -54,6 +54,10 @@
   int OnUpdateSurfaces(pdx::Message& message,
                        const std::map<int, DisplaySurfaceAttributes>& updates);
 
+  pdx::BorrowedChannelHandle OnSetupPoseBuffer(pdx::Message& message,
+                                               size_t extended_region_size,
+                                               int usage);
+
   // Called by the display service to indicate changes to display surfaces that
   // the display manager should evaluate.
   void OnDisplaySurfaceChange();
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index fdb84c5..da7281b 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -18,10 +18,20 @@
 using android::pdx::rpc::DispatchRemoteMethod;
 using android::pdx::rpc::WrapBuffer;
 
+namespace {
+
+constexpr char kPersistentPoseBufferName[] = "DvrPersistentPoseBuffer";
+const int kPersistentPoseBufferUserId = 0;
+const int kPersistentPoseBufferGroupId = 0;
+const size_t kTimingDataSizeOffset = 128;
+
+}  // anonymous namespace
+
 namespace android {
 namespace dvr {
 
-DisplayService::DisplayService() : DisplayService(nullptr) {}
+DisplayService::DisplayService()
+    : DisplayService(nullptr) {}
 
 DisplayService::DisplayService(Hwc2::Composer* hidl)
     : BASE("DisplayService", Endpoint::Create(DisplayRPC::kClientPath)),
@@ -74,21 +84,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);
       return 0;
 
+    case DisplayRPC::GetPoseBuffer::Opcode:
+      DispatchRemoteMethod<DisplayRPC::GetPoseBuffer>(
+          *this, &DisplayService::OnGetPoseBuffer, message);
+      return 0;
+
     // Direct the surface specific messages to the surface instance.
     case DisplayRPC::CreateBufferQueue::Opcode:
     case DisplayRPC::SetAttributes::Opcode:
@@ -182,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();
@@ -254,6 +249,15 @@
   compositor->UpdateHeadMountMetrics(head_mount_metrics);
 }
 
+pdx::LocalChannelHandle DisplayService::OnGetPoseBuffer(pdx::Message& message) {
+  if (pose_buffer_) {
+    return pose_buffer_->CreateConsumer().take();
+  }
+
+  pdx::rpc::RemoteMethodError(message, EAGAIN);
+  return {};
+}
+
 // Calls the message handler for the DisplaySurface associated with this
 // channel.
 int DisplayService::HandleSurfaceMessage(pdx::Message& message) {
@@ -290,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.
@@ -321,7 +325,20 @@
     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(
+    size_t extended_region_size, int usage) {
+  if (!pose_buffer_) {
+    pose_buffer_ = BufferProducer::Create(
+        kPersistentPoseBufferName, kPersistentPoseBufferUserId,
+        kPersistentPoseBufferGroupId, usage,
+        extended_region_size + kTimingDataSizeOffset);
+  }
+
+  return pose_buffer_->GetChannelHandle().Borrow();
 }
 
 void DisplayService::OnHardwareComposerRefresh() {
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 9d116c1..2a71b4a 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -36,7 +36,10 @@
 
   // 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);
 
   template <class A>
   void ForEachDisplaySurface(A action) const {
@@ -60,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();
 
@@ -80,14 +78,14 @@
   DisplayService(android::Hwc2::Composer* hidl);
 
   SystemDisplayMetrics OnGetMetrics(pdx::Message& message);
-  int OnCreateSurface(pdx::Message& message, int width, int height,
-                      int format, int usage, DisplaySurfaceFlags flags);
+  int OnCreateSurface(pdx::Message& message, int width, int height, int format,
+                      int usage, DisplaySurfaceFlags flags);
 
   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);
+  void OnSetViewerParams(pdx::Message& message,
+                         const ViewerParams& view_params);
+  pdx::LocalChannelHandle OnGetPoseBuffer(pdx::Message& message);
 
   // Called by DisplaySurface to signal that a surface property has changed and
   // the display manager should be notified.
@@ -100,6 +98,8 @@
 
   HardwareComposer hardware_composer_;
   DisplayConfigurationUpdateNotifier update_notifier_;
+
+  std::unique_ptr<BufferProducer> pose_buffer_;
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 66808ca..66e9925 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -40,7 +40,8 @@
       manager_visible_(false),
       manager_z_order_(0),
       manager_blur_(0.0f),
-      layer_order_(0) {}
+      layer_order_(0),
+      allocated_buffer_index_(0) {}
 
 DisplaySurface::~DisplaySurface() {
   ALOGD_IF(LOCAL_TRACE,
@@ -104,6 +105,14 @@
       return;
     }
 
+    // Save buffer index, associated with the buffer id so that it can be looked
+    // up later.
+    int buffer_id = buffer_consumer->id();
+    if (buffer_id_to_index_.find(buffer_id) == buffer_id_to_index_.end()) {
+      buffer_id_to_index_[buffer_id] = allocated_buffer_index_;
+      ++allocated_buffer_index_;
+    }
+
     if (!IsVisible()) {
       ATRACE_NAME("DropFrameOnInvisibleSurface");
       ALOGD_IF(TRACE,
@@ -171,6 +180,17 @@
   return buffer;
 }
 
+uint32_t DisplaySurface::GetRenderBufferIndex(int buffer_id) {
+  std::lock_guard<std::mutex> autolock(lock_);
+
+  if (buffer_id_to_index_.find(buffer_id) == buffer_id_to_index_.end()) {
+    ALOGW("DisplaySurface::GetRenderBufferIndex: unknown buffer_id %d.",
+          buffer_id);
+    return 0;
+  }
+  return buffer_id_to_index_[buffer_id];
+}
+
 bool DisplaySurface::IsBufferAvailable() {
   std::lock_guard<std::mutex> autolock(lock_);
   DequeueBuffersLocked();
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index feb173e..d31a3a9 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -60,10 +60,7 @@
     }
   }
 
-  uint32_t GetRenderBufferIndex(int buffer_id) {
-    return buffer_id_to_index_[buffer_id];
-  }
-
+  uint32_t GetRenderBufferIndex(int buffer_id);
   bool IsBufferAvailable();
   bool IsBufferPosted();
   AcquiredBuffer AcquireCurrentBuffer();
@@ -172,6 +169,8 @@
   float manager_blur_;
   int layer_order_;
 
+  // The monotonically increasing index for allocated buffers in this surface.
+  uint32_t allocated_buffer_index_;
   // Maps from the buffer id to the corresponding allocated buffer index.
   std::unordered_map<int, uint32_t> buffer_id_to_index_;
 };
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/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 4c4cd4e..7715c46 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -652,9 +652,8 @@
 #define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
 #define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3156
 #define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
-#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3158
-#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3159
-#define EGL_READS_DONE_TIME_ANDROID 0x315A
+#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3158
+#define EGL_READS_DONE_TIME_ANDROID 0x3159
 #ifdef EGL_EGLEXT_PROTOTYPES
 EGLAPI EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
 EGLAPI EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index d124c89..b00d401 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -2075,7 +2075,6 @@
     nsecs_t* gpuCompositionDoneTime = nullptr;
     nsecs_t* lastRefreshStartTime = nullptr;
     nsecs_t* displayPresentTime = nullptr;
-    nsecs_t* displayRetireTime = nullptr;
     nsecs_t* dequeueReadyTime = nullptr;
     nsecs_t* releaseTime = nullptr;
 
@@ -2102,9 +2101,6 @@
             case EGL_DISPLAY_PRESENT_TIME_ANDROID:
                 displayPresentTime = &values[i];
                 break;
-            case EGL_DISPLAY_RETIRE_TIME_ANDROID:
-                displayRetireTime = &values[i];
-                break;
             case EGL_DEQUEUE_READY_TIME_ANDROID:
                 dequeueReadyTime = &values[i];
                 break;
@@ -2119,7 +2115,7 @@
     int ret = native_window_get_frame_timestamps(s->getNativeWindow(), frameId,
             requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
             lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime,
-            displayRetireTime, dequeueReadyTime, releaseTime);
+            dequeueReadyTime, releaseTime);
 
     switch (ret) {
         case 0:
@@ -2170,19 +2166,10 @@
         case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
         case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
         case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID:
+        case EGL_DISPLAY_PRESENT_TIME_ANDROID:
         case EGL_DEQUEUE_READY_TIME_ANDROID:
         case EGL_READS_DONE_TIME_ANDROID:
             return EGL_TRUE;
-        case EGL_DISPLAY_PRESENT_TIME_ANDROID: {
-            int value = 0;
-            window->query(window, NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value);
-            return value == 0 ? EGL_FALSE : EGL_TRUE;
-        }
-        case EGL_DISPLAY_RETIRE_TIME_ANDROID: {
-            int value = 0;
-            window->query(window, NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE, &value);
-            return value == 0 ? EGL_FALSE : EGL_TRUE;
-        }
         default:
             return EGL_FALSE;
     }
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index e32d9e6..61b9b66 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -46,8 +46,8 @@
     and display of window surfaces.
 
     Some examples of how this might be used:
-        - The display present or retire time can be used to calculate end-to-end
-          latency of the entire graphics pipeline.
+        - The display present time can be used to calculate end-to-end latency
+          of the entire graphics pipeline.
         - The queue time and rendering complete time can be used to determine
           how long the application's rendering took to complete. Likewise, the
           composition start time and finish time can be used to determine how
@@ -92,9 +92,8 @@
     EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
     EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3156
     EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
-    EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3158
-    EGL_DEQUEUE_READY_TIME_ANDROID 0x3159
-    EGL_READS_DONE_TIME_ANDROID 0x315A
+    EGL_DEQUEUE_READY_TIME_ANDROID 0x3158
+    EGL_READS_DONE_TIME_ANDROID 0x3159
 
 Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
 "Surface Attributes", page 43:
@@ -195,8 +194,6 @@
           didn't do any rendering.
         - EGL_DISPLAY_PRESENT_TIME_ANDROID - The time at which this frame
           started to scan out to the physical display.
-        - EGL_DISPLAY_RETIRE_TIME_ANDROID - The time at which this frame was
-          replaced by the next frame on-screen.
         - EGL_DEQUEUE_READY_TIME_ANDROID - The time when the buffer became
           available for reuse as a buffer the client can target without
           blocking. This is generally the point when all read commands of the
@@ -225,6 +222,9 @@
 
 Revision History
 
+#6 (Brian Anderson, March 16, 2017)
+    - Remove DISPLAY_RETIRE_TIME_ANDROID.
+
 #5 (Brian Anderson, January 13, 2017)
     - Add eglGetCompositorTimingANDROID.
 
diff --git a/opengl/specs/README b/opengl/specs/README
index a7a9785..27289e4 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -30,7 +30,6 @@
 0x3155               EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
 0x3156               EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
 0x3157               EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3158               EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3159               EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x315A               EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x315B - 0x315F      (unused)
+0x3158               EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3159               EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x315A - 0x315F      (unused)
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index b8ca812..22a4616 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2416,7 +2416,7 @@
             struct KeyReplacement replacement = {keyCode, args->deviceId};
             mReplacedKeys.add(replacement, newKeyCode);
             keyCode = newKeyCode;
-            metaState &= ~AMETA_META_ON;
+            metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
         }
     } else if (args->action == AKEY_EVENT_ACTION_UP) {
         // In order to maintain a consistent stream of up and down events, check to see if the key
@@ -2428,7 +2428,7 @@
         if (index >= 0) {
             keyCode = mReplacedKeys.valueAt(index);
             mReplacedKeys.removeItemsAt(index);
-            metaState &= ~AMETA_META_ON;
+            metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
         }
     }
 
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index a6ea750..647a4c0 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
@@ -65,10 +64,6 @@
         DisplayHardware/HWComposer_hwc1.cpp
 endif
 
-ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),)
-    LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS)
-endif
-
 LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
 
 LOCAL_HEADER_LIBRARIES := \
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 11df4e2..c3b48ca 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -64,9 +64,8 @@
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 
-static bool useTripleFramebuffer = getBool<
-        ISurfaceFlingerConfigs,
-        &ISurfaceFlingerConfigs::useTripleFramebuffer>(false);
+static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs,
+        &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) == 3;
 
 #if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle)
 // Dummy implementation in case it is missing.
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 9a0e94e..1b598f8 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -40,10 +40,7 @@
 
 #include "FramebufferSurface.h"
 #include "HWComposer.h"
-
-#ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS
-#define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2)
-#endif
+#include "../SurfaceFlinger.h"
 
 // ----------------------------------------------------------------------------
 namespace android {
@@ -88,7 +85,8 @@
     mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp));
     mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
 #endif
-    mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1);
+    mConsumer->setMaxAcquiredBufferCount(
+            SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
 }
 
 status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 23b7a45..09434f6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -617,10 +617,6 @@
     return mDisplayData[displayId].lastPresentFence;
 }
 
-bool HWComposer::presentFenceRepresentsStartOfScanout() const {
-    return mAdapter ? false : true;
-}
-
 sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
         const std::shared_ptr<HWC2::Layer>& layer) const {
     if (!isValidDisplay(displayId)) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 117db4a..81f1619 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -126,11 +126,6 @@
     // get the present fence received from the last call to present.
     sp<Fence> getPresentFence(int32_t displayId) const;
 
-    // Returns true if the present fence represents the start of the display
-    // controller's scan out. This should be true for all HWC2 implementations,
-    // except for the wrapper around HWC1 implementations.
-    bool presentFenceRepresentsStartOfScanout() const;
-
     // Get last release fence for the given layer
     sp<Fence> getLayerReleaseFence(int32_t displayId,
             const std::shared_ptr<HWC2::Layer>& layer) const;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 861a7d9..2755206 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1883,7 +1883,6 @@
 
 bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
         const std::shared_ptr<FenceTime>& presentFence,
-        const std::shared_ptr<FenceTime>& retireFence,
         const CompositorTiming& compositorTiming) {
     mAcquireTimeline.updateSignalTimes();
     mReleaseTimeline.updateSignalTimes();
@@ -1898,10 +1897,6 @@
         Mutex::Autolock lock(mFrameEventHistoryMutex);
         mFrameEventHistory.addPostComposition(mCurrentFrameNumber,
                 glDoneFence, presentFence, compositorTiming);
-        if (mPreviousFrameNumber != 0) {
-            mFrameEventHistory.addRetire(mPreviousFrameNumber,
-                    retireFence);
-        }
     }
 
     // Update mFrameTracker.
@@ -1921,9 +1916,6 @@
     if (presentFence->isValid()) {
         mFrameTracker.setActualPresentFence(
                 std::shared_ptr<FenceTime>(presentFence));
-    } else if (retireFence->isValid()) {
-        mFrameTracker.setActualPresentFence(
-                std::shared_ptr<FenceTime>(retireFence));
     } else {
         // The HWC doesn't support present fences, so use the refresh
         // timestamp instead.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index afe6074..cee9e3c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -308,7 +308,6 @@
      */
     bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
             const std::shared_ptr<FenceTime>& presentFence,
-            const std::shared_ptr<FenceTime>& retireFence,
             const CompositorTiming& compositorTiming);
 
 #ifdef USE_HWC2
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 06dd903..a63b9b4 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,8 @@
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
 bool SurfaceFlinger::hasSyncFramework;
+bool SurfaceFlinger::useVrFlinger;
+int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -136,7 +137,6 @@
         mVisibleRegionsDirty(false),
         mGeometryInvalid(false),
         mAnimCompositionPending(false),
-        mVrModeSupported(0),
         mDebugRegion(0),
         mDebugDDMS(0),
         mDebugDisableHWC(0),
@@ -156,10 +156,8 @@
         mFrameBuckets(),
         mTotalTime(0),
         mLastSwapTime(0),
-        mNumLayers(0)
-#ifdef USE_HWC2
-        ,mEnterVrMode(false)
-#endif
+        mNumLayers(0),
+        mVrFlingerRequestsDisplay(false)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -184,13 +182,16 @@
     maxVirtualDisplaySize = getUInt64<ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::maxVirtualDisplaySize>(0);
 
+    // Vr flinger is only enabled on Daydream ready devices.
+    useVrFlinger = getBool< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::useVrFlinger>(false);
+
+    maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
+
     // 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 +232,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 +358,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 +370,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 +565,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();
 
@@ -643,23 +646,6 @@
     return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
 }
 
-status_t SurfaceFlinger::getSupportedFrameTimestamps(
-        std::vector<FrameEvent>* outSupported) const {
-    *outSupported = {
-        FrameEvent::REQUESTED_PRESENT,
-        FrameEvent::ACQUIRE,
-        FrameEvent::LATCH,
-        FrameEvent::FIRST_REFRESH_START,
-        FrameEvent::LAST_REFRESH_START,
-        FrameEvent::GPU_COMPOSITION_DONE,
-        getHwComposer().presentFenceRepresentsStartOfScanout() ?
-                FrameEvent::DISPLAY_PRESENT : FrameEvent::DISPLAY_RETIRE,
-        FrameEvent::DEQUEUE_READY,
-        FrameEvent::RELEASE,
-    };
-    return NO_ERROR;
-}
-
 status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
         Vector<DisplayInfo>* configs) {
     if ((configs == NULL) || (display.get() == NULL)) {
@@ -1213,14 +1199,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");
@@ -1228,25 +1217,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();
 
@@ -1268,12 +1245,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() ==
@@ -1285,6 +1256,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;
@@ -1484,19 +1460,11 @@
     }
     mGlCompositionDoneTimeline.updateSignalTimes();
 
-    sp<Fence> displayFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
-    auto displayFenceTime = std::make_shared<FenceTime>(displayFence);
-    mDisplayTimeline.push(displayFenceTime);
+    sp<Fence> presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
+    auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
+    mDisplayTimeline.push(presentFenceTime);
     mDisplayTimeline.updateSignalTimes();
 
-    const std::shared_ptr<FenceTime>* presentFenceTime = &FenceTime::NO_FENCE;
-    const std::shared_ptr<FenceTime>* retireFenceTime = &FenceTime::NO_FENCE;
-    if (mHwc->presentFenceRepresentsStartOfScanout()) {
-        presentFenceTime = &displayFenceTime;
-    } else {
-        retireFenceTime = &displayFenceTime;
-    }
-
     nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
     nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
 
@@ -1504,7 +1472,7 @@
     // when we started doing work for this frame, but that should be okay
     // since updateCompositorTiming has snapping logic.
     updateCompositorTiming(
-        vsyncPhase, vsyncInterval, refreshStartTime, displayFenceTime);
+        vsyncPhase, vsyncInterval, refreshStartTime, presentFenceTime);
     CompositorTiming compositorTiming;
     {
         std::lock_guard<std::mutex> lock(mCompositorTimingLock);
@@ -1513,15 +1481,15 @@
 
     mDrawingState.traverseInZOrder([&](Layer* layer) {
         bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
-                *presentFenceTime, *retireFenceTime, compositorTiming);
+                presentFenceTime, compositorTiming);
         if (frameLatched) {
             recordBufferingStats(layer->getName().string(),
                     layer->getOccupancyHistory(false));
         }
     });
 
-    if (displayFence->isValid()) {
-        if (mPrimaryDispSync.addPresentFence(displayFence)) {
+    if (presentFence->isValid()) {
+        if (mPrimaryDispSync.addPresentFence(presentFence)) {
             enableHardwareVsync();
         } else {
             disableHardwareVsync(false);
@@ -1537,9 +1505,9 @@
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
 
-        if (displayFenceTime->isValid()) {
+        if (presentFenceTime->isValid()) {
             mAnimFrameTracker.setActualPresentFence(
-                    std::move(displayFenceTime));
+                    std::move(presentFenceTime));
         } else {
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
@@ -3262,6 +3230,8 @@
     result.appendFormat(" FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
     result.appendFormat(" MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
     result.appendFormat(" RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
+    result.appendFormat(" NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
+                        maxFrameBufferAcquiredBuffers);
     result.append("]");
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 921ecf6..581bbfd 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;
@@ -148,6 +147,10 @@
     // Equal to min(max_height, max_width).
     static uint64_t maxVirtualDisplaySize;
 
+    // Controls the number of buffers SurfaceFlinger will allocate for use in
+    // FramebufferSurface
+    static int64_t maxFrameBufferAcquiredBuffers;
+
     static char const* getServiceName() ANDROID_API {
         return "SurfaceFlinger";
     }
@@ -211,7 +214,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.
@@ -256,8 +258,6 @@
     virtual void bootFinished();
     virtual bool authenticateSurfaceTexture(
         const sp<IGraphicBufferProducer>& bufferProducer) const;
-    virtual status_t getSupportedFrameTimestamps(
-            std::vector<FrameEvent>* outSupported) const;
     virtual sp<IDisplayEventConnection> createDisplayEventConnection();
     virtual status_t captureScreen(const sp<IBinder>& display,
             const sp<IGraphicBufferProducer>& producer,
@@ -532,9 +532,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
 
     /* ------------------------------------------------------------------------
@@ -604,7 +603,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;
@@ -701,9 +699,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/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index e8147cf..cd02b13 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -116,6 +116,7 @@
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
 bool SurfaceFlinger::hasSyncFramework;
+int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -175,6 +176,9 @@
     useHwcForRgbToYuv = getBool< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::useHwcForRGBtoYUV>(false);
 
+    maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
+
     char value[PROPERTY_VALUE_MAX];
 
     property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
@@ -643,22 +647,6 @@
     return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
 }
 
-status_t SurfaceFlinger::getSupportedFrameTimestamps(
-        std::vector<FrameEvent>* outSupported) const {
-    *outSupported = {
-        FrameEvent::REQUESTED_PRESENT,
-        FrameEvent::ACQUIRE,
-        FrameEvent::LATCH,
-        FrameEvent::FIRST_REFRESH_START,
-        FrameEvent::LAST_REFRESH_START,
-        FrameEvent::GPU_COMPOSITION_DONE,
-        FrameEvent::DISPLAY_RETIRE,
-        FrameEvent::DEQUEUE_READY,
-        FrameEvent::RELEASE,
-    };
-    return NO_ERROR;
-}
-
 status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
         Vector<DisplayInfo>* configs) {
     if ((configs == NULL) || (display.get() == NULL)) {
@@ -1261,9 +1249,8 @@
     }
     mGlCompositionDoneTimeline.updateSignalTimes();
 
-    sp<Fence> displayFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY);
-    const std::shared_ptr<FenceTime>& presentFenceTime = FenceTime::NO_FENCE;
-    auto retireFenceTime = std::make_shared<FenceTime>(displayFence);
+    sp<Fence> retireFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY);
+    auto retireFenceTime = std::make_shared<FenceTime>(retireFence);
     mDisplayTimeline.push(retireFenceTime);
     mDisplayTimeline.updateSignalTimes();
 
@@ -1282,16 +1269,18 @@
     }
 
     mDrawingState.traverseInZOrder([&](Layer* layer) {
+        // TODO(brianderson): The retire fence is incorrectly passed in as the
+        // present fence. Fix this if this file lives on.
         bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
-                presentFenceTime, retireFenceTime, compositorTiming);
+                retireFenceTime, compositorTiming);
         if (frameLatched) {
             recordBufferingStats(layer->getName().string(),
                     layer->getOccupancyHistory(false));
         }
     });
 
-    if (displayFence->isValid()) {
-        if (mPrimaryDispSync.addPresentFence(displayFence)) {
+    if (retireFence->isValid()) {
+        if (mPrimaryDispSync.addPresentFence(retireFence)) {
             enableHardwareVsync();
         } else {
             disableHardwareVsync(false);
@@ -3039,6 +3028,8 @@
     result.appendFormat(" FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
     result.appendFormat(" MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
     result.appendFormat(" RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
+    result.appendFormat(" NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
+                        maxFrameBufferAcquiredBuffers);
     result.append("]");
 }
 
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/bufferhubd/bufferhubd.rc b/services/vr/bufferhubd/bufferhubd.rc
index ceedf1a..65b7293 100644
--- a/services/vr/bufferhubd/bufferhubd.rc
+++ b/services/vr/bufferhubd/bufferhubd.rc
@@ -2,5 +2,5 @@
   class core
   user system
   group system
-  cpuset /
+  writepid /dev/cpuset/tasks
 
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
new file mode 100644
index 0000000..629d65b
--- /dev/null
+++ b/services/vr/hardware_composer/Android.bp
@@ -0,0 +1,96 @@
+cc_library_static {
+  name: "libvr_hwc-binder",
+  srcs: [
+    "aidl/android/dvr/IVrComposer.aidl",
+    "aidl/android/dvr/IVrComposerCallback.aidl",
+    "aidl/android/dvr/parcelable_composer_frame.cpp",
+    "aidl/android/dvr/parcelable_composer_layer.cpp",
+    "aidl/android/dvr/parcelable_unique_fd.cpp",
+  ],
+  aidl: {
+    include_dirs: ["frameworks/native/services/vr/hardware_composer/aidl"],
+    export_aidl_headers: true,
+  },
+  export_include_dirs: ["aidl"],
+  shared_libs: [
+    "libbinder",
+    "libui",
+    "libutils",
+    "libvrhwc",
+  ],
+}
+
+cc_library_static {
+  name: "libvr_hwc-impl",
+  srcs: [
+    "vr_composer.cpp",
+  ],
+  static_libs: [
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libui",
+    "libutils",
+    "libvrhwc",
+  ],
+  export_shared_lib_headers: [
+    "libvrhwc",
+  ],
+  cflags: [
+    "-DLOG_TAG=\"vr_hwc\"",
+  ],
+}
+
+cc_binary {
+  name: "vr_hwc",
+  srcs: [
+    "vr_hardware_composer_service.cpp"
+  ],
+  static_libs: [
+    "libvr_hwc-impl",
+    // NOTE: This needs to be included after the *-impl lib otherwise the
+    // symbols in the *-binder library get optimized out.
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "android.dvr.composer@1.0",
+    "android.hardware.graphics.composer@2.1",
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libhardware",
+    "libhwbinder",
+    "libui",
+    "libutils",
+    "libvrhwc",
+  ],
+  cflags: [
+    "-DLOG_TAG=\"vr_hwc\"",
+  ],
+  init_rc: [
+    "vr_hwc.rc",
+  ],
+}
+
+cc_test {
+  name: "vr_hwc_test",
+  gtest: true,
+  srcs: ["tests/vr_composer_test.cpp"],
+  static_libs: [
+    "libgtest",
+    "libvr_hwc-impl",
+    // NOTE: This needs to be included after the *-impl lib otherwise the
+    // symbols in the *-binder library get optimized out.
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libui",
+    "libutils",
+  ],
+}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
new file mode 100644
index 0000000..5fd5c36
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
@@ -0,0 +1,20 @@
+package android.dvr;
+
+import android.dvr.IVrComposerCallback;
+
+/**
+ * Service interface exposed by VR HWC exposed to system apps which allows one
+ * system app to connect to get SurfaceFlinger's outputs (all displays). This
+ * is active when SurfaceFlinger is in VR mode, where all 2D output is
+ * redirected to VR HWC.
+ *
+ * @hide */
+interface IVrComposer
+{
+  const String SERVICE_NAME = "vr_hwc";
+
+  /**
+   * Registers a callback used to receive frame notifications.
+   */
+  void registerObserver(in IVrComposerCallback callback);
+}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl
new file mode 100644
index 0000000..aa70de1
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl
@@ -0,0 +1,22 @@
+package android.dvr;
+
+import android.dvr.ParcelableComposerFrame;
+import android.dvr.ParcelableUniqueFd;
+
+/**
+ * A system app will implement and register this callback with VRComposer
+ * to receive the layers SurfaceFlinger presented when in VR mode.
+ *
+ * @hide */
+interface IVrComposerCallback {
+  /**
+   * Called by the VR HWC service when a new frame is ready to be presented.
+   *
+   * @param frame The new frame VR HWC wants to present.
+   * @return A fence FD used to signal when the previous frame is no longer
+   * used by the client. This may be an invalid fence (-1) if the client is not
+   * using the previous frame, in which case the previous frame may be re-used
+   * at any point in time.
+   */
+  ParcelableUniqueFd onNewFrame(in ParcelableComposerFrame frame);
+}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl
new file mode 100644
index 0000000..84abc19
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl
@@ -0,0 +1,3 @@
+package android.dvr;
+
+parcelable ParcelableComposerFrame cpp_header "android/dvr/parcelable_composer_frame.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl
new file mode 100644
index 0000000..a200345
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl
@@ -0,0 +1,3 @@
+package android.dvr;
+
+parcelable ParcelableComposerLayer cpp_header "android/dvr/parcelable_composer_layer.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl
new file mode 100644
index 0000000..eee9d13
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl
@@ -0,0 +1,3 @@
+package android.dvr;
+
+parcelable ParcelableUniqueFd cpp_header "android/dvr/parcelable_unique_fd.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
new file mode 100644
index 0000000..cb3e49d
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
@@ -0,0 +1,53 @@
+#include "aidl/android/dvr/parcelable_composer_frame.h"
+
+#include <binder/Parcel.h>
+
+#include "aidl/android/dvr/parcelable_composer_layer.h"
+
+namespace android {
+namespace dvr {
+
+ParcelableComposerFrame::ParcelableComposerFrame() {}
+
+ParcelableComposerFrame::ParcelableComposerFrame(
+    const ComposerView::Frame& frame)
+    : frame_(frame) {}
+
+ParcelableComposerFrame::~ParcelableComposerFrame() {}
+
+status_t ParcelableComposerFrame::writeToParcel(Parcel* parcel) const {
+  status_t ret = parcel->writeUint64(frame_.display_id);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeBool(frame_.removed);
+  if (ret != OK) return ret;
+
+  std::vector<ParcelableComposerLayer> layers;
+  for (size_t i = 0; i < frame_.layers.size(); ++i)
+    layers.push_back(ParcelableComposerLayer(frame_.layers[i]));
+
+  ret = parcel->writeParcelableVector(layers);
+
+  return ret;
+}
+
+status_t ParcelableComposerFrame::readFromParcel(const Parcel* parcel) {
+  status_t ret = parcel->readUint64(&frame_.display_id);
+  if (ret != OK) return ret;
+
+  ret = parcel->readBool(&frame_.removed);
+  if (ret != OK) return ret;
+
+  std::vector<ParcelableComposerLayer> layers;
+  ret = parcel->readParcelableVector(&layers);
+  if (ret != OK) return ret;
+
+  frame_.layers.clear();
+  for (size_t i = 0; i < layers.size(); ++i)
+    frame_.layers.push_back(layers[i].layer());
+
+  return ret;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
new file mode 100644
index 0000000..b478bb5
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
@@ -0,0 +1,28 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
+
+#include <binder/Parcelable.h>
+#include <impl/vr_hwc.h>
+
+namespace android {
+namespace dvr {
+
+class ParcelableComposerFrame : public Parcelable {
+ public:
+  ParcelableComposerFrame();
+  ParcelableComposerFrame(const ComposerView::Frame& frame);
+  ~ParcelableComposerFrame() override;
+
+  ComposerView::Frame frame() const { return frame_; }
+
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  ComposerView::Frame frame_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
new file mode 100644
index 0000000..34e2b7e
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
@@ -0,0 +1,166 @@
+#include "aidl/android/dvr/parcelable_composer_layer.h"
+
+#include <binder/Parcel.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferMapper.h>
+
+namespace android {
+namespace dvr {
+namespace {
+
+sp<GraphicBuffer> GetBufferFromHandle(native_handle_t* handle) {
+  uint32_t width = 0, height = 0, stride = 0, layer_count = 1;
+  uint64_t producer_usage = 0, consumer_usage = 0;
+  int32_t format = 0;
+
+  GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+  // Need to register |handle| otherwise we can't read its properties.
+  if (mapper.registerBuffer(handle) != OK) {
+    ALOGE("Failed to register buffer");
+    return nullptr;
+  }
+
+  if (mapper.getDimensions(handle, &width, &height) ||
+      mapper.getStride(handle, &stride) ||
+      mapper.getFormat(handle, &format) ||
+      mapper.getProducerUsage(handle, &producer_usage) ||
+      mapper.getConsumerUsage(handle, &consumer_usage)) {
+    ALOGE("Failed to read handle properties");
+    return nullptr;
+  }
+
+  // This will only succeed if gralloc has GRALLOC1_CAPABILITY_LAYERED_BUFFERS
+  // capability. Otherwise assume a count of 1.
+  mapper.getLayerCount(handle, &layer_count);
+
+  sp<GraphicBuffer> buffer = new GraphicBuffer(
+      width, height, format, layer_count, producer_usage, consumer_usage,
+      stride, handle, true);
+
+  return buffer;
+}
+
+}  // namespace
+
+ParcelableComposerLayer::ParcelableComposerLayer() {}
+
+ParcelableComposerLayer::ParcelableComposerLayer(
+    const ComposerView::ComposerLayer& layer) : layer_(layer) {}
+
+ParcelableComposerLayer::~ParcelableComposerLayer() {}
+
+status_t ParcelableComposerLayer::writeToParcel(Parcel* parcel) const {
+  status_t ret = parcel->writeUint64(layer_.id);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeNativeHandle(layer_.buffer->getNativeBuffer()->handle);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeBool(layer_.fence->isValid());
+  if (ret != OK) return ret;
+
+  if (layer_.fence->isValid()) {
+    ret = parcel->writeFileDescriptor(layer_.fence->dup(), true);
+    if (ret != OK) return ret;
+  }
+
+  ret = parcel->writeInt32(layer_.display_frame.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(layer_.display_frame.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(layer_.display_frame.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(layer_.display_frame.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(static_cast<int32_t>(layer_.blend_mode));
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.alpha);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeUint32(layer_.type);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeUint32(layer_.app_id);
+  if (ret != OK) return ret;
+
+  return OK;
+}
+
+status_t ParcelableComposerLayer::readFromParcel(const Parcel* parcel) {
+  status_t ret = parcel->readUint64(&layer_.id);
+  if (ret != OK) return ret;
+
+  native_handle* handle = parcel->readNativeHandle();
+  if (!handle) return BAD_VALUE;
+
+  layer_.buffer = GetBufferFromHandle(handle);
+  if (!layer_.buffer.get()) return BAD_VALUE;
+
+  bool has_fence = 0;
+  ret = parcel->readBool(&has_fence);
+  if (ret != OK) return ret;
+
+  if (has_fence)
+    layer_.fence = new Fence(dup(parcel->readFileDescriptor()));
+  else
+    layer_.fence = new Fence();
+
+  ret = parcel->readInt32(&layer_.display_frame.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(&layer_.display_frame.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(&layer_.display_frame.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(&layer_.display_frame.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(reinterpret_cast<int32_t*>(&layer_.blend_mode));
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.alpha);
+  if (ret != OK) return ret;
+
+  ret = parcel->readUint32(&layer_.type);
+  if (ret != OK) return ret;
+
+  ret = parcel->readUint32(&layer_.app_id);
+  if (ret != OK) return ret;
+
+  return OK;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
new file mode 100644
index 0000000..4cf48f1
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
@@ -0,0 +1,30 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
+
+#include <binder/Parcelable.h>
+#include <impl/vr_hwc.h>
+
+#include <memory>
+
+namespace android {
+namespace dvr {
+
+class ParcelableComposerLayer : public Parcelable {
+ public:
+  ParcelableComposerLayer();
+  ParcelableComposerLayer(const ComposerView::ComposerLayer& layer);
+  ~ParcelableComposerLayer() override;
+
+  ComposerView::ComposerLayer layer() const { return layer_; }
+
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  ComposerView::ComposerLayer layer_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp
new file mode 100644
index 0000000..9486f3c
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp
@@ -0,0 +1,37 @@
+#include "android/dvr/parcelable_unique_fd.h"
+
+#include <binder/Parcel.h>
+
+namespace android {
+namespace dvr {
+
+ParcelableUniqueFd::ParcelableUniqueFd() {}
+
+ParcelableUniqueFd::ParcelableUniqueFd(const base::unique_fd& fence)
+    : fence_(dup(fence.get())) {}
+
+ParcelableUniqueFd::~ParcelableUniqueFd() {}
+
+status_t ParcelableUniqueFd::writeToParcel(Parcel* parcel) const {
+  status_t ret = parcel->writeBool(fence_.get() >= 0);
+  if (ret != OK) return ret;
+
+  if (fence_.get() >= 0)
+    ret = parcel->writeUniqueFileDescriptor(fence_);
+
+  return ret;
+}
+
+status_t ParcelableUniqueFd::readFromParcel(const Parcel* parcel) {
+  bool has_fence = 0;
+  status_t ret = parcel->readBool(&has_fence);
+  if (ret != OK) return ret;
+
+  if (has_fence)
+    ret = parcel->readUniqueFileDescriptor(&fence_);
+
+  return ret;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
new file mode 100644
index 0000000..daf9e6d
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
@@ -0,0 +1,34 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace dvr {
+
+// Provide a wrapper to serialized base::unique_fd. The wrapper also handles the
+// case where the FD is invalid (-1), unlike FileDescriptor which expects a
+// valid FD.
+class ParcelableUniqueFd : public Parcelable {
+ public:
+  ParcelableUniqueFd();
+  ParcelableUniqueFd(const base::unique_fd& fence);
+  ~ParcelableUniqueFd() override;
+
+  void set_fence(const base::unique_fd& fence) {
+    fence_.reset(dup(fence.get()));
+  }
+  base::unique_fd fence() const { return base::unique_fd(dup(fence_.get())); }
+
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  base::unique_fd fence_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
new file mode 100644
index 0000000..cfc2708
--- /dev/null
+++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp
@@ -0,0 +1,147 @@
+#include <android/dvr/BnVrComposerCallback.h>
+#include <binder/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <sys/eventfd.h>
+#include <vr_composer.h>
+
+namespace android {
+namespace dvr {
+namespace {
+
+const char kVrDisplayName[] = "VrDisplay_Test";
+
+class TestComposerCallback : public BnVrComposerCallback {
+ public:
+  TestComposerCallback() {}
+  ~TestComposerCallback() override = default;
+
+  ComposerView::Frame last_frame() const { return last_frame_; }
+
+  binder::Status onNewFrame(
+      const ParcelableComposerFrame& frame,
+      ParcelableUniqueFd* /* fence */) override {
+    last_frame_ = frame.frame();
+    return binder::Status::ok();
+  }
+
+ private:
+  ComposerView::Frame last_frame_;
+
+  TestComposerCallback(const TestComposerCallback&) = delete;
+  void operator=(const TestComposerCallback&) = delete;
+};
+
+class TestComposerCallbackWithFence : public TestComposerCallback {
+ public:
+  ~TestComposerCallbackWithFence() override = default;
+
+  binder::Status onNewFrame(
+      const ParcelableComposerFrame& frame,
+      ParcelableUniqueFd* fence) override {
+    binder::Status status = TestComposerCallback::onNewFrame(frame, fence);
+
+    base::unique_fd fd(eventfd(0, 0));
+    EXPECT_LE(0, fd.get());
+    fence->set_fence(fd);
+
+    return status;
+  }
+};
+
+sp<GraphicBuffer> CreateBuffer() {
+  return new GraphicBuffer(600, 400, PIXEL_FORMAT_RGBA_8888,
+                           GraphicBuffer::USAGE_HW_TEXTURE);
+}
+
+}  // namespace
+
+class VrComposerTest : public testing::Test {
+ public:
+  VrComposerTest() : composer_(new VrComposer()) {}
+  ~VrComposerTest() override = default;
+
+  sp<IVrComposer> GetComposerProxy() const {
+    sp<IServiceManager> sm(defaultServiceManager());
+    return interface_cast<IVrComposer>(sm->getService(String16(kVrDisplayName)));
+  }
+
+  void SetUp() override {
+    sp<IServiceManager> sm(defaultServiceManager());
+    EXPECT_EQ(OK,
+              sm->addService(String16(kVrDisplayName), composer_, false));
+  }
+
+ protected:
+  sp<VrComposer> composer_;
+
+  VrComposerTest(const VrComposerTest&) = delete;
+  void operator=(const VrComposerTest&) = delete;
+};
+
+TEST_F(VrComposerTest, TestWithoutObserver) {
+  sp<IVrComposer> composer = GetComposerProxy();
+  ComposerView::Frame frame;
+
+  base::unique_fd fence = composer_->OnNewFrame(frame);
+  ASSERT_EQ(-1, fence.get());
+}
+
+TEST_F(VrComposerTest, TestWithObserver) {
+  sp<IVrComposer> composer = GetComposerProxy();
+  sp<TestComposerCallback> callback = new TestComposerCallback();
+  ASSERT_TRUE(composer->registerObserver(callback).isOk());
+
+  ComposerView::Frame frame;
+  base::unique_fd fence = composer_->OnNewFrame(frame);
+  ASSERT_EQ(-1, fence.get());
+}
+
+TEST_F(VrComposerTest, TestWithOneLayer) {
+  sp<IVrComposer> composer = GetComposerProxy();
+  sp<TestComposerCallback> callback = new TestComposerCallbackWithFence();
+  ASSERT_TRUE(composer->registerObserver(callback).isOk());
+
+  ComposerView::Frame frame;
+  frame.display_id = 1;
+  frame.removed = false;
+  frame.layers.push_back(ComposerView::ComposerLayer{
+    .id = 1,
+    .buffer = CreateBuffer(),
+    .fence = new Fence(eventfd(0, 0)),
+    .display_frame = {0, 0, 600, 400},
+    .crop = {0.0f, 0.0f, 600.0f, 400.0f},
+    .blend_mode = IComposerClient::BlendMode::NONE,
+    .alpha = 1.0f,
+    .type = 1,
+    .app_id = 1,
+  });
+  base::unique_fd fence = composer_->OnNewFrame(frame);
+  ASSERT_LE(0, fence.get());
+
+  ComposerView::Frame received_frame = callback->last_frame();
+  ASSERT_EQ(frame.display_id, received_frame.display_id);
+  ASSERT_EQ(frame.removed, received_frame.removed);
+  ASSERT_EQ(1u, received_frame.layers.size());
+  ASSERT_EQ(frame.layers[0].id, received_frame.layers[0].id);
+  ASSERT_NE(nullptr, received_frame.layers[0].buffer.get());
+  ASSERT_TRUE(received_frame.layers[0].fence->isValid());
+  ASSERT_EQ(frame.layers[0].display_frame.left,
+            received_frame.layers[0].display_frame.left);
+  ASSERT_EQ(frame.layers[0].display_frame.top,
+            received_frame.layers[0].display_frame.top);
+  ASSERT_EQ(frame.layers[0].display_frame.right,
+            received_frame.layers[0].display_frame.right);
+  ASSERT_EQ(frame.layers[0].display_frame.bottom,
+            received_frame.layers[0].display_frame.bottom);
+  ASSERT_EQ(frame.layers[0].crop.left, received_frame.layers[0].crop.left);
+  ASSERT_EQ(frame.layers[0].crop.top, received_frame.layers[0].crop.top);
+  ASSERT_EQ(frame.layers[0].crop.right, received_frame.layers[0].crop.right);
+  ASSERT_EQ(frame.layers[0].crop.bottom, received_frame.layers[0].crop.bottom);
+  ASSERT_EQ(frame.layers[0].blend_mode, received_frame.layers[0].blend_mode);
+  ASSERT_EQ(frame.layers[0].alpha, received_frame.layers[0].alpha);
+  ASSERT_EQ(frame.layers[0].type, received_frame.layers[0].type);
+  ASSERT_EQ(frame.layers[0].app_id, received_frame.layers[0].app_id);
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
new file mode 100644
index 0000000..c15f8fd
--- /dev/null
+++ b/services/vr/hardware_composer/vr_composer.cpp
@@ -0,0 +1,46 @@
+#include "vr_composer.h"
+
+namespace android {
+namespace dvr {
+
+VrComposer::VrComposer() {}
+
+VrComposer::~VrComposer() {}
+
+binder::Status VrComposer::registerObserver(
+    const sp<IVrComposerCallback>& callback) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  if (callback_.get()) {
+    ALOGE("Failed to register callback, already registered");
+    return binder::Status::fromStatusT(ALREADY_EXISTS);
+  }
+
+  callback_ = callback;
+  IInterface::asBinder(callback_)->linkToDeath(this);
+  return binder::Status::ok();
+}
+
+base::unique_fd VrComposer::OnNewFrame(const ComposerView::Frame& frame) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  if (!callback_.get())
+    return base::unique_fd();
+
+  ParcelableComposerFrame parcelable_frame(frame);
+  ParcelableUniqueFd fence;
+  binder::Status ret = callback_->onNewFrame(parcelable_frame, &fence);
+  if (!ret.isOk())
+    ALOGE("Failed to send new frame: %s", ret.toString8().string());
+
+  return fence.fence();
+}
+
+void VrComposer::binderDied(const wp<IBinder>& /* who */) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  callback_ = nullptr;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
new file mode 100644
index 0000000..93d1f2b
--- /dev/null
+++ b/services/vr/hardware_composer/vr_composer.h
@@ -0,0 +1,48 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
+
+#include <android/dvr/BnVrComposer.h>
+#include <impl/vr_hwc.h>
+
+namespace android {
+namespace dvr {
+
+class VrComposerCallback;
+
+// Implementation of the IVrComposer service used to notify VR Window Manager
+// when SurfaceFlinger presents 2D UI changes.
+//
+// VR HWC updates the presented frame via the ComposerView::Observer interface.
+// On notification |callback_| is called to update VR Window Manager.
+// NOTE: If VR Window Manager isn't connected, the notification is a no-op.
+class VrComposer
+    : public BnVrComposer,
+      public ComposerView::Observer,
+      public IBinder::DeathRecipient {
+ public:
+  VrComposer();
+  ~VrComposer() override;
+
+  // BnVrComposer:
+  binder::Status registerObserver(
+      const sp<IVrComposerCallback>& callback) override;
+
+  // ComposerView::Observer:
+  base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
+
+ private:
+  // IBinder::DeathRecipient:
+  void binderDied(const wp<IBinder>& who) override;
+
+  std::mutex mutex_;
+
+  sp<IVrComposerCallback> callback_;
+
+  VrComposer(const VrComposer&) = delete;
+  void operator=(const VrComposer&) = delete;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  //  ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
new file mode 100644
index 0000000..9591748
--- /dev/null
+++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright 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 <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <hwbinder/IPCThreadState.h>
+#include <impl/vr_hwc.h>
+#include <inttypes.h>
+
+#include "vr_composer.h"
+
+int main() {
+  android::ProcessState::self()->startThreadPool();
+
+  // Register the hwbinder HWC HAL service used by SurfaceFlinger while in VR
+  // mode.
+  const char instance[] = "vr_hwcomposer";
+  android::sp<IComposer> service =
+      android::dvr::HIDL_FETCH_IComposer(instance);
+
+  LOG_ALWAYS_FATAL_IF(!service.get(), "Failed to get service");
+  LOG_ALWAYS_FATAL_IF(service->isRemote(), "Service is remote");
+
+  LOG_ALWAYS_FATAL_IF(service->registerAsService(instance) != android::OK,
+                      "Failed to register service");
+
+  android::sp<android::dvr::VrComposer> composer =
+      new android::dvr::VrComposer();
+
+  android::dvr::ComposerView* composer_view =
+      android::dvr::GetComposerViewFromIComposer(service.get());
+  composer_view->RegisterObserver(composer.get());
+
+  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+
+  // Register the binder service used by VR Window Manager service to receive
+  // frame information from VR HWC HAL.
+  android::status_t status = sm->addService(
+      android::dvr::VrComposer::SERVICE_NAME(), composer.get(),
+      false /* allowIsolated */);
+  LOG_ALWAYS_FATAL_IF(status != android::OK,
+                      "VrDisplay service failed to start: %" PRId32, status);
+
+  android::hardware::ProcessState::self()->startThreadPool();
+  android::hardware::IPCThreadState::self()->joinThreadPool();
+
+  composer_view->UnregisterObserver(composer.get());
+
+  return 0;
+}
diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc
new file mode 100644
index 0000000..5d3c4f7
--- /dev/null
+++ b/services/vr/hardware_composer/vr_hwc.rc
@@ -0,0 +1,6 @@
+service vr_hwc /system/bin/vr_hwc
+  class hal
+  user system
+  group system graphics
+  onrestart restart surfaceflinger
+  disabled
diff --git a/services/vr/performanced/performanced.rc b/services/vr/performanced/performanced.rc
index 754c97f..5042982 100644
--- a/services/vr/performanced/performanced.rc
+++ b/services/vr/performanced/performanced.rc
@@ -2,4 +2,4 @@
   class core
   user root
   group system readproc
-  cpuset /
+  writepid /dev/cpuset/tasks
diff --git a/services/vr/sensord/sensord.rc b/services/vr/sensord/sensord.rc
index d868a7e..f8d28fd 100644
--- a/services/vr/sensord/sensord.rc
+++ b/services/vr/sensord/sensord.rc
@@ -6,4 +6,4 @@
   class core
   user system
   group system camera sdcard_rw
-  cpuset /system
+  writepid /dev/cpuset/system/tasks
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index 2e2f622..191bcfb 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -45,6 +45,8 @@
     // reported when the previous client performs any touchpad action.
     ALOGE("pid=%ld replaces %ld", static_cast<long>(pid),
           static_cast<long>(client_pid_));
+    client_pid_ = pid;
+    return binder::Status::ok();
   }
   client_pid_ = pid;
   if (const status_t error = touchpad_->Attach()) {
diff --git a/services/vr/virtual_touchpad/virtual_touchpad.rc b/services/vr/virtual_touchpad/virtual_touchpad.rc
index b4f9f00..99315ef 100644
--- a/services/vr/virtual_touchpad/virtual_touchpad.rc
+++ b/services/vr/virtual_touchpad/virtual_touchpad.rc
@@ -2,4 +2,4 @@
   class core
   user system
   group system input
-  cpuset /system
+  writepid /dev/cpuset/system/tasks
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index eb9f407..7c61076 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;
 }
@@ -274,15 +274,13 @@
     }
     controller_data_provider_->UnlockControllerData();
     if (shmem_controller_active_) {
-      // TODO(kpschoedel): change to ALOGV or remove.
-      ALOGI("Controller shmem orientation: %f %f %f %f",
+      ALOGV("Controller shmem orientation: %f %f %f %f",
             controller_orientation_.x(), controller_orientation_.y(),
             controller_orientation_.z(), controller_orientation_.w());
       if (shmem_controller_buttons_) {
-        ALOGI("Controller shmem buttons: %017" PRIX64,
+        ALOGV("Controller shmem buttons: %017" PRIX64,
             shmem_controller_buttons_);
       }
-      return;
     }
   }
 }
@@ -315,7 +313,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_;
diff --git a/services/vr/vr_window_manager/composer/Android.bp b/services/vr/vr_window_manager/composer/Android.bp
index 4349269..f28818a 100644
--- a/services/vr/vr_window_manager/composer/Android.bp
+++ b/services/vr/vr_window_manager/composer/Android.bp
@@ -34,6 +34,14 @@
     "libutils",
   ],
 
+  export_static_lib_headers: [
+    "libhwcomposer-client",
+  ],
+
+  export_shared_lib_headers: [
+    "android.hardware.graphics.composer@2.1",
+  ],
+
   export_include_dirs: ["."],
 
   cflags: [
diff --git a/services/vr/vr_window_manager/composer_view/vr_composer_view.rc b/services/vr/vr_window_manager/composer_view/vr_composer_view.rc
index abb5265..bd9982b 100644
--- a/services/vr/vr_window_manager/composer_view/vr_composer_view.rc
+++ b/services/vr/vr_window_manager/composer_view/vr_composer_view.rc
@@ -2,4 +2,4 @@
   class core
   user system
   group system graphics
-  cpuset /system
+  writepid /dev/cpuset/system/tasks
diff --git a/services/vr/vr_window_manager/vr_wm.rc b/services/vr/vr_window_manager/vr_wm.rc
index 951515b..e515bb7 100644
--- a/services/vr/vr_window_manager/vr_wm.rc
+++ b/services/vr/vr_window_manager/vr_wm.rc
@@ -2,4 +2,4 @@
   class core
   user system
   group system graphics input
-  cpuset /system
+  writepid /dev/cpuset/system/tasks
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index f7695ea..5017e14 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -314,7 +314,6 @@
             // supported, at startup time (since it may not be
             // supported):
             &actual_present_time,
-            NULL,  //&display_retire_time,
             NULL,  //&dequeue_ready_time,
             NULL /*&reads_done_time*/);