Merge "Clean up possible null dereference warning."
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 595fbab..d61cbc9 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -446,7 +446,10 @@
 // Set the default size of cmdline hashtable
 static bool setCmdlineSize()
 {
-    return writeStr(k_traceCmdlineSizePath, "8192");
+    if (fileExists(k_traceCmdlineSizePath)) {
+        return writeStr(k_traceCmdlineSizePath, "8192");
+    }
+    return true;
 }
 
 // Set the clock to the best available option while tracing. Use 'boot' if it's
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 1e0f6f8..526fd19 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -15,6 +15,8 @@
     chown root shell /sys/kernel/tracing/options/overwrite
     chown root shell /sys/kernel/debug/tracing/options/print-tgid
     chown root shell /sys/kernel/tracing/options/print-tgid
+    chown root shell /sys/kernel/debug/tracing/saved_cmdlines_size
+    chown root shell /sys/kernel/tracing/saved_cmdlines_size
     chown root shell /sys/kernel/debug/tracing/events/sched/sched_switch/enable
     chown root shell /sys/kernel/tracing/events/sched/sched_switch/enable
     chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
@@ -65,6 +67,8 @@
     chmod 0664 /sys/kernel/tracing/options/overwrite
     chmod 0664 /sys/kernel/debug/tracing/options/print-tgid
     chmod 0664 /sys/kernel/tracing/options/print-tgid
+    chmod 0664 /sys/kernel/debug/tracing/saved_cmdlines_size
+    chmod 0664 /sys/kernel/tracing/saved_cmdlines_size
     chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
     chmod 0664 /sys/kernel/tracing/events/sched/sched_switch/enable
     chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 745361c..95dc8dd 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -72,6 +72,7 @@
 
 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
 #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
+#define BLK_DEV_SYS_DIR "/sys/block"
 
 #define RAFT_DIR "/data/misc/raft"
 #define RECOVERY_DIR "/cache/recovery"
@@ -539,7 +540,6 @@
     return false;
 }
 
-static const char mmcblk0[] = "/sys/block/mmcblk0/";
 unsigned long worst_write_perf = 20000; /* in KB/s */
 
 //
@@ -653,11 +653,13 @@
         return 0;
     }
 
-    if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
-        path += sizeof(mmcblk0) - 1;
+    if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
+        path += sizeof(BLK_DEV_SYS_DIR) - 1;
     }
 
-    printf("%s: %s\n", path, buffer);
+    printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
+           "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
+           "W-wait", "in-fli", "activ", "T-wait", path, buffer);
     free(buffer);
 
     if (fields[__STAT_IO_TICKS]) {
@@ -694,9 +696,9 @@
                                  / fields[__STAT_IO_TICKS];
 
         if (!write_perf && !write_ios) {
-            printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
+            printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
         } else {
-            printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
+            printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
                    read_ios, write_perf, write_ios, queue);
         }
 
@@ -1061,12 +1063,37 @@
     }
 }
 
+static void DumpBlockStatFiles() {
+    DurationReporter duration_reporter("DUMP BLOCK STAT");
+
+    std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
+
+    if (dirptr == nullptr) {
+        MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
+        return;
+    }
+
+    printf("------ DUMP BLOCK STAT ------\n\n");
+    while (struct dirent *d = readdir(dirptr.get())) {
+        if ((d->d_name[0] == '.')
+         && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
+          || (d->d_name[1] == '\0'))) {
+            continue;
+        }
+        const std::string new_path =
+            android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
+        printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
+        dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
+        printf("\n");
+    }
+     return;
+}
 static void dumpstate() {
     DurationReporter duration_reporter("DUMPSTATE");
 
     dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
     RunCommand("UPTIME", {"uptime"});
-    dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
+    DumpBlockStatFiles();
     dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
     DumpFile("MEMORY INFO", "/proc/meminfo");
     RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
@@ -1161,8 +1188,6 @@
     RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
     RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
     RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
-    RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
-               CommandOptions::WithTimeout(20).Build());
 
     RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
                CommandOptions::WithTimeout(10).Build());
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 22ad718..e3021d8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1698,7 +1698,7 @@
                 collectQuotaStats(device, userId, appId, nullptr, &extStats);
             }
         }
-        appSize = extStats.dataSize + extStats.cacheSize;
+        appSize = extStats.dataSize;
         ATRACE_END();
     } else {
         ATRACE_BEGIN("manual");
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 4ecbf92..baa05d0 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -863,6 +863,8 @@
         return false;
     }
 
+    // As a security measure we want to write the profile information with the reduced capabilities
+    // of the package user id. So we fork and drop capabilities in the child.
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -900,7 +902,9 @@
         if (flock(out_fd.get(), LOCK_UN) != 0) {
             PLOG(WARNING) << "Error unlocking profile " << data_profile_location;
         }
-        exit(0);
+        // Use _exit since we don't want to run the global destructors in the child.
+        // b/62597429
+        _exit(0);
     }
     /* parent */
     int return_code = wait_child(pid);
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 87b9104..7c6cfd9 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -244,7 +244,18 @@
     mOut << std::endl;
 }
 
+static inline bool findAndBumpVersion(vintf::ManifestHal* hal, const vintf::Version& version) {
+    for (vintf::Version& v : hal->versions) {
+        if (v.majorVer == version.majorVer) {
+            v.minorVer = std::max(v.minorVer, version.minorVer);
+            return true;
+        }
+    }
+    return false;
+}
+
 void ListCommand::dumpVintf() const {
+    using vintf::operator|=;
     mOut << "<!-- " << std::endl
          << "    This is a skeleton device manifest. Notes: " << std::endl
          << "    1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
@@ -252,7 +263,9 @@
          << "       only hwbinder is shown." << std::endl
          << "    3. It is likely that HALs in passthrough transport does not have" << std::endl
          << "       <interface> declared; users will have to write them by hand." << std::endl
-         << "    4. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
+         << "    4. A HAL with lower minor version can be overridden by a HAL with" << std::endl
+         << "       higher minor version if they have the same name and major version." << std::endl
+         << "    5. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
          << "       is removed from the manifest file and written by assemble_vintf" << std::endl
          << "       at build time." << std::endl
          << "-->" << std::endl;
@@ -316,17 +329,19 @@
             for (vintf::ManifestHal *hal : manifest.getHals(fqName.package())) {
                 if (hal->transport() != transport) {
                     if (transport != vintf::Transport::PASSTHROUGH) {
-                        mErr << "Fatal: should not reach here. Generated result may be wrong."
+                        mErr << "Fatal: should not reach here. Generated result may be wrong for '"
+                             << hal->name << "'."
                              << std::endl;
                     }
                     done = true;
                     break;
                 }
-                if (hal->hasVersion(version)) {
+                if (findAndBumpVersion(hal, version)) {
                     if (&table != &mImplementationsTable) {
                         hal->interfaces[interfaceName].name = interfaceName;
                         hal->interfaces[interfaceName].instances.insert(instanceName);
                     }
+                    hal->transportArch.arch |= arch;
                     done = true;
                     break;
                 }
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index 9557b4f..32ce59a 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -25,6 +25,7 @@
 #include <utils/Timers.h>
 
 #include <binder/IInterface.h>
+#include <gui/ISurfaceComposer.h>
 
 // ----------------------------------------------------------------------------
 
@@ -83,7 +84,8 @@
      * or requestNextVsync to receive them.
      * Other events start being delivered immediately.
      */
-    DisplayEventReceiver();
+    DisplayEventReceiver(
+            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
 
     /*
      * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 90de114..9fb7580 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -267,6 +267,8 @@
     // discardFreeBuffers releases all currently-free buffers held by the BufferQueue, in order to
     // reduce the memory consumption of the BufferQueue to the minimum possible without
     // discarding data.
+    // The consumer invoking this method is responsible for calling getReleasedBuffers() after this
+    // call to free up any of its locally cached buffers.
     virtual status_t discardFreeBuffers() = 0;
 
     // dump state into a string
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 1112973..f80ba00 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -72,6 +72,11 @@
         eRotate270  = 3
     };
 
+    enum VsyncSource {
+        eVsyncSourceApp = 0,
+        eVsyncSourceSurfaceFlinger = 1
+    };
+
     /* create connection with surface flinger, requires
      * ACCESS_SURFACE_FLINGER permission
      */
@@ -89,7 +94,8 @@
             const sp<IGraphicBufferProducer>& parent) = 0;
 
     /* return an IDisplayEventConnection */
-    virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0;
+    virtual sp<IDisplayEventConnection> createDisplayEventConnection(
+            VsyncSource vsyncSource = eVsyncSourceApp) = 0;
 
     /* create a virtual display
      * requires ACCESS_SURFACE_FLINGER permission.
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 712a323..8bb705c 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -135,6 +135,7 @@
             const sp<SurfaceControl>& control, Parcel* parcel);
 
     sp<Surface> getSurface() const;
+    sp<Surface> createSurface() const;
     sp<IBinder> getHandle() const;
 
     status_t clearLayerFrameStats() const;
@@ -155,6 +156,7 @@
 
     ~SurfaceControl();
 
+    sp<Surface> generateSurfaceLocked() const;
     status_t validate() const;
     void destroy();
 
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index b39ecc5..3d94a02 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -629,41 +629,49 @@
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    sp<IConsumerListener> listener;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
 
-    if (mCore->mIsAbandoned) {
-        BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
-        return NO_INIT;
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
+            return NO_INIT;
+        }
+
+        if (mCore->mSharedBufferMode) {
+            BQ_LOGE("detachNextBuffer: cannot detach a buffer in shared buffer "
+                    "mode");
+            return BAD_VALUE;
+        }
+
+        mCore->waitWhileAllocatingLocked();
+
+        if (mCore->mFreeBuffers.empty()) {
+            return NO_MEMORY;
+        }
+
+        int found = mCore->mFreeBuffers.front();
+        mCore->mFreeBuffers.remove(found);
+        mCore->mFreeSlots.insert(found);
+
+        BQ_LOGV("detachNextBuffer detached slot %d", found);
+
+        *outBuffer = mSlots[found].mGraphicBuffer;
+        *outFence = mSlots[found].mFence;
+        mCore->clearBufferSlotLocked(found);
+        VALIDATE_CONSISTENCY();
+        listener = mCore->mConsumerListener;
     }
 
-    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
+    if (listener != NULL) {
+        listener->onBuffersReleased();
     }
 
-    if (mCore->mSharedBufferMode) {
-        BQ_LOGE("detachNextBuffer: cannot detach a buffer in shared buffer "
-            "mode");
-        return BAD_VALUE;
-    }
-
-    mCore->waitWhileAllocatingLocked();
-
-    if (mCore->mFreeBuffers.empty()) {
-        return NO_MEMORY;
-    }
-
-    int found = mCore->mFreeBuffers.front();
-    mCore->mFreeBuffers.remove(found);
-    mCore->mFreeSlots.insert(found);
-
-    BQ_LOGV("detachNextBuffer detached slot %d", found);
-
-    *outBuffer = mSlots[found].mGraphicBuffer;
-    *outFence = mSlots[found].mFence;
-    mCore->clearBufferSlotLocked(found);
-    VALIDATE_CONSISTENCY();
-
     return NO_ERROR;
 }
 
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 5c6158c..c2b10a9 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -253,7 +253,18 @@
         CB_LOGE("discardFreeBuffers: ConsumerBase is abandoned!");
         return NO_INIT;
     }
-    return mConsumer->discardFreeBuffers();
+    status_t err = mConsumer->discardFreeBuffers();
+    if (err != OK) {
+        return err;
+    }
+    uint64_t mask;
+    mConsumer->getReleasedBuffers(&mask);
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        if (mask & (1ULL << i)) {
+            freeBufferLocked(i);
+        }
+    }
+    return OK;
 }
 
 void ConsumerBase::dumpState(String8& result) const {
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 1507d51..1757ec1 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -32,10 +32,10 @@
 
 // ---------------------------------------------------------------------------
 
-DisplayEventReceiver::DisplayEventReceiver() {
+DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     if (sf != NULL) {
-        mEventConnection = sf->createDisplayEventConnection();
+        mEventConnection = sf->createDisplayEventConnection(vsyncSource);
         if (mEventConnection != NULL) {
             mDataChannel = std::make_unique<gui::BitTube>();
             mEventConnection->stealReceiveChannel(mDataChannel.get());
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 2516fb8..0a0d112 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -201,7 +201,7 @@
         return NO_ERROR;
     }
 
-    virtual sp<IDisplayEventConnection> createDisplayEventConnection()
+    virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource)
     {
         Parcel data, reply;
         sp<IDisplayEventConnection> result;
@@ -210,6 +210,7 @@
         if (err != NO_ERROR) {
             return result;
         }
+        data.writeInt32(static_cast<int32_t>(vsyncSource));
         err = remote()->transact(
                 BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
                 data, &reply);
@@ -586,7 +587,8 @@
         }
         case CREATE_DISPLAY_EVENT_CONNECTION: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IDisplayEventConnection> connection(createDisplayEventConnection());
+            sp<IDisplayEventConnection> connection(createDisplayEventConnection(
+                    static_cast<ISurfaceComposer::VsyncSource>(data.readInt32())));
             reply->writeStrongBinder(IInterface::asBinder(connection));
             return NO_ERROR;
         }
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index bf8a815..58bd273 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -237,17 +237,30 @@
     return parcel->writeStrongBinder(IInterface::asBinder(bp));
 }
 
+sp<Surface> SurfaceControl::generateSurfaceLocked() const
+{
+    // This surface is always consumed by SurfaceFlinger, so the
+    // producerControlledByApp value doesn't matter; using false.
+    mSurfaceData = new Surface(mGraphicBufferProducer, false);
+
+    return mSurfaceData;
+}
+
 sp<Surface> SurfaceControl::getSurface() const
 {
     Mutex::Autolock _l(mLock);
     if (mSurfaceData == 0) {
-        // This surface is always consumed by SurfaceFlinger, so the
-        // producerControlledByApp value doesn't matter; using false.
-        mSurfaceData = new Surface(mGraphicBufferProducer, false);
+        return generateSurfaceLocked();
     }
     return mSurfaceData;
 }
 
+sp<Surface> SurfaceControl::createSurface() const
+{
+    Mutex::Autolock _l(mLock);
+    return generateSurfaceLocked();
+}
+
 sp<IBinder> SurfaceControl::getHandle() const
 {
     Mutex::Autolock lock(mLock);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 81820de..e18af17 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -465,7 +465,8 @@
             const sp<IGraphicBufferProducer>& /* parent */) override {
         return nullptr;
     }
-    sp<IDisplayEventConnection> createDisplayEventConnection() override {
+    sp<IDisplayEventConnection> createDisplayEventConnection(ISurfaceComposer::VsyncSource)
+            override {
         return nullptr;
     }
     sp<IBinder> createDisplay(const String8& /*displayName*/,
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 2f4b996..ed292e7 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -44,12 +44,12 @@
     if (!outBuffer || !desc)
         return BAD_VALUE;
 
-    int format = AHardwareBuffer_convertToPixelFormat(desc->format);
-    if (format == 0) {
-        ALOGE("Invalid pixel format %u", desc->format);
+    if (!AHardwareBuffer_isValidPixelFormat(desc->format)) {
+        ALOGE("Invalid AHardwareBuffer pixel format %u (%#x))", desc->format, desc->format);
         return BAD_VALUE;
     }
 
+    int format = AHardwareBuffer_convertToPixelFormat(desc->format);
     if (desc->rfu0 != 0 || desc->rfu1 != 0) {
         ALOGE("AHardwareBuffer_Desc::rfu fields must be 0");
         return BAD_VALUE;
@@ -296,32 +296,95 @@
     return (mask & bitsToCheck) == bitsToCheck && bitsToCheck;
 }
 
-uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format) {
+bool AHardwareBuffer_isValidPixelFormat(uint32_t format) {
+    static_assert(HAL_PIXEL_FORMAT_RGBA_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_RGBX_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_RGB_565 == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_RGB_888 == AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_RGBA_FP16 == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_RGBA_1010102 == AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_Y8 == AHARDWAREBUFFER_FORMAT_Y8,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_Y16 == AHARDWAREBUFFER_FORMAT_Y16,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_RAW16 == AHARDWAREBUFFER_FORMAT_RAW16,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_RAW10 == AHARDWAREBUFFER_FORMAT_RAW10,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_RAW12 == AHARDWAREBUFFER_FORMAT_RAW12,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_RAW_OPAQUE == AHARDWAREBUFFER_FORMAT_RAW_OPAQUE,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED == AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_YCBCR_422_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_YCBCR_444_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_FLEX_RGB_888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_FLEX_RGBA_8888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I,
+            "HAL and AHardwareBuffer pixel format don't match");
+
     switch (format) {
-        case HAL_PIXEL_FORMAT_RGBA_8888:    return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
-        case HAL_PIXEL_FORMAT_RGBX_8888:    return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
-        case HAL_PIXEL_FORMAT_RGB_565:      return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
-        case HAL_PIXEL_FORMAT_RGB_888:      return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
-        case HAL_PIXEL_FORMAT_RGBA_FP16:    return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
-        case HAL_PIXEL_FORMAT_RGBA_1010102: return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
-        case HAL_PIXEL_FORMAT_BLOB:         return AHARDWAREBUFFER_FORMAT_BLOB;
-        default:ALOGE("Unknown pixel format %u", format);
-            return 0;
+        case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+        case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+        case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+        case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+        case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+        case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+        case AHARDWAREBUFFER_FORMAT_BLOB:
+            // VNDK formats only -- unfortunately we can't differentiate from where we're called
+        case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
+        case AHARDWAREBUFFER_FORMAT_YV12:
+        case AHARDWAREBUFFER_FORMAT_Y8:
+        case AHARDWAREBUFFER_FORMAT_Y16:
+        case AHARDWAREBUFFER_FORMAT_RAW16:
+        case AHARDWAREBUFFER_FORMAT_RAW10:
+        case AHARDWAREBUFFER_FORMAT_RAW12:
+        case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE:
+        case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED:
+        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
+        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422:
+        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444:
+        case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8:
+        case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8:
+        case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
+        case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
+        case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
+            return true;
+
+        default:
+            return false;
     }
 }
 
-uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t format) {
-    switch (format) {
-        case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:         return HAL_PIXEL_FORMAT_RGBA_8888;
-        case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:         return HAL_PIXEL_FORMAT_RGBX_8888;
-        case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:           return HAL_PIXEL_FORMAT_RGB_565;
-        case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:           return HAL_PIXEL_FORMAT_RGB_888;
-        case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:     return HAL_PIXEL_FORMAT_RGBA_FP16;
-        case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:      return HAL_PIXEL_FORMAT_RGBA_1010102;
-        case AHARDWAREBUFFER_FORMAT_BLOB:                   return HAL_PIXEL_FORMAT_BLOB;
-        default:ALOGE("Unknown AHardwareBuffer format %u", format);
-            return 0;
-    }
+uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t hal_format) {
+    return hal_format;
+}
+
+uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t ahardwarebuffer_format) {
+    return ahardwarebuffer_format;
 }
 
 uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) {
diff --git a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
index ed6b169..71f5634 100644
--- a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
+++ b/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
@@ -32,11 +32,21 @@
 
 namespace android {
 
+// whether this AHardwareBuffer format is valid
+bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format);
+
+// convert AHardwareBuffer format to HAL format (note: this is a no-op)
 uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format);
+
+// convert HAL format to AHardwareBuffer format (note: this is a no-op)
 uint32_t AHardwareBuffer_convertToPixelFormat(uint32_t format);
-uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage);
+
+// convert AHardwareBuffer usage bits to HAL usage bits (note: this is a no-op)
 uint64_t AHardwareBuffer_convertFromGrallocUsageBits(uint64_t usage);
 
+// convert HAL usage bits to AHardwareBuffer usage bits  (note: this is a no-op)
+uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage);
+
 class GraphicBuffer;
 const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(const AHardwareBuffer* buffer);
 GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer);
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index dc2dcbe..802edcc 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -26,6 +26,49 @@
 
 const native_handle_t* AHardwareBuffer_getNativeHandle(const AHardwareBuffer* buffer);
 
+
+/**
+ * Buffer pixel formats.
+ */
+enum {
+    /* for future proofing, keep these in sync with system/graphics-base.h */
+
+    /* same as HAL_PIXEL_FORMAT_BGRA_8888 */
+    AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM           = 5,
+    /* same as HAL_PIXEL_FORMAT_YV12 */
+    AHARDWAREBUFFER_FORMAT_YV12                     = 0x32315659,
+    /* same as HAL_PIXEL_FORMAT_Y8 */
+    AHARDWAREBUFFER_FORMAT_Y8                       = 0x20203859,
+    /* same as HAL_PIXEL_FORMAT_Y16 */
+    AHARDWAREBUFFER_FORMAT_Y16                      = 0x20363159,
+    /* same as HAL_PIXEL_FORMAT_RAW16 */
+    AHARDWAREBUFFER_FORMAT_RAW16                    = 0x20,
+    /* same as HAL_PIXEL_FORMAT_RAW10 */
+    AHARDWAREBUFFER_FORMAT_RAW10                    = 0x25,
+    /* same as HAL_PIXEL_FORMAT_RAW12 */
+    AHARDWAREBUFFER_FORMAT_RAW12                    = 0x26,
+    /* same as HAL_PIXEL_FORMAT_RAW_OPAQUE */
+    AHARDWAREBUFFER_FORMAT_RAW_OPAQUE               = 0x24,
+    /* same as HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED */
+    AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED   = 0x22,
+    /* same as HAL_PIXEL_FORMAT_YCBCR_420_888 */
+    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420             = 0x23,
+    /* same as HAL_PIXEL_FORMAT_YCBCR_422_888 */
+    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422             = 0x27,
+    /* same as HAL_PIXEL_FORMAT_YCBCR_444_888 */
+    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444             = 0x28,
+    /* same as HAL_PIXEL_FORMAT_FLEX_RGB_888 */
+    AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8              = 0x29,
+    /* same as HAL_PIXEL_FORMAT_FLEX_RGBA_8888 */
+    AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8            = 0x2A,
+    /* same as HAL_PIXEL_FORMAT_YCBCR_422_SP */
+    AHARDWAREBUFFER_FORMAT_YCbCr_422_SP             = 0x10,
+    /* same as HAL_PIXEL_FORMAT_YCRCB_420_SP */
+    AHARDWAREBUFFER_FORMAT_YCrCb_420_SP             = 0x11,
+    /* same as HAL_PIXEL_FORMAT_YCBCR_422_I */
+    AHARDWAREBUFFER_FORMAT_YCbCr_422_I              = 0x14,
+};
+
 __END_DECLS
 
 #endif /* ANDROID_VNDK_NATIVEWINDOW_AHARDWAREBUFFER_H */
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index c2d477e..0a537a3 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -30,7 +30,7 @@
         mName(name), mHandle(0), mType(0),
         mMinValue(0), mMaxValue(0), mResolution(0),
         mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0),
-        mFifoMaxEventCount(0), mRequiredAppOp(0),
+        mFifoMaxEventCount(0), mRequiredAppOp(-1),
         mMaxDelay(0), mFlags(0) {
 }
 
@@ -412,6 +412,10 @@
     return (mFlags & SENSOR_FLAG_DYNAMIC_SENSOR) != 0;
 }
 
+bool Sensor::isDataInjectionSupported() const {
+    return (mFlags & SENSOR_FLAG_DATA_INJECTION) != 0;
+}
+
 bool Sensor::hasAdditionalInfo() const {
     return (mFlags & SENSOR_FLAG_ADDITIONAL_INFO) != 0;
 }
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 043e635..6926f7f 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -90,6 +90,7 @@
     uint32_t getFlags() const;
     bool isWakeUpSensor() const;
     bool isDynamicSensor() const;
+    bool isDataInjectionSupported() const;
     bool hasAdditionalInfo() const;
     int32_t getHighestDirectReportRateLevel() const;
     bool isDirectChannelTypeSupported(int32_t sharedMemType) const;
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 87dbaf4..e149803 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "Gralloc2"
 
+#include <hidl/ServiceManagement.h>
 #include <hwbinder/IPCThreadState.h>
 #include <ui/Gralloc2.h>
 
@@ -250,4 +251,17 @@
 
 } // namespace Gralloc2
 
+namespace {
+// Load the IMapper implementation library when this shared library is loaded, rather than when
+// we (lazily) create the Gralloc2::Mapper instance. Since these libraries will all be needed by
+// nearly all apps, this allows us to load them in Zygote rather than on each app launch.
+class PreloadMapperImpl {
+public:
+    PreloadMapperImpl() {
+        android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
+    }
+};
+static PreloadMapperImpl preloadMapperImpl;
+} // namespace
+
 } // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
index a54579f..140ffc5 100644
--- a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
@@ -52,8 +52,6 @@
   void operator=(NativeBuffer&) = delete;
 };
 
-// NativeBufferProducer is an implementation of ANativeWindowBuffer backed by a
-// BufferProducer.
 class NativeBufferProducer : public android::ANativeObjectBase<
                                  ANativeWindowBuffer, NativeBufferProducer,
                                  android::LightRefBase<NativeBufferProducer>> {
@@ -71,20 +69,25 @@
     ANativeWindowBuffer::stride = buffer_->stride();
     ANativeWindowBuffer::format = buffer_->format();
     ANativeWindowBuffer::usage = buffer_->usage();
-    handle = buffer_->native_handle();
+    ANativeWindowBuffer::handle = buffer_->native_handle();
+    if (display_) {
+      image_khr_ =
+          eglCreateImageKHR(display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                            static_cast<ANativeWindowBuffer*>(this), nullptr);
+    } else {
+      image_khr_ = EGL_NO_IMAGE_KHR;
+    }
   }
 
   explicit NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer)
       : NativeBufferProducer(buffer, nullptr, 0) {}
 
   virtual ~NativeBufferProducer() {
-    for (EGLImageKHR egl_image : egl_images_) {
-      if (egl_image != EGL_NO_IMAGE_KHR)
-        eglDestroyImageKHR(display_, egl_image);
-    }
+    if (image_khr_ != EGL_NO_IMAGE_KHR)
+      eglDestroyImageKHR(display_, image_khr_);
   }
 
-  EGLImageKHR image_khr(int index) const { return egl_images_[index]; }
+  EGLImageKHR image_khr() const { return image_khr_; }
   std::shared_ptr<BufferProducer> buffer() const { return buffer_; }
   int release_fence() const { return release_fence_.Get(); }
   uint32_t surface_buffer_index() const { return surface_buffer_index_; }
@@ -112,7 +115,7 @@
 
   std::shared_ptr<BufferProducer> buffer_;
   pdx::LocalHandle release_fence_;
-  std::vector<EGLImageKHR> egl_images_;
+  EGLImageKHR image_khr_;
   uint32_t surface_buffer_index_;
   EGLDisplay display_;
 
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index a53c8b0..f0ef299 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -442,46 +442,78 @@
   SetupQueue(status.get());
 }
 
-Status<void> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
-                                           uint32_t layer_count,
-                                           uint32_t format, uint64_t usage,
-                                           size_t* out_slot) {
-  if (out_slot == nullptr) {
-    ALOGE("ProducerQueue::AllocateBuffer: Parameter out_slot cannot be null.");
-    return ErrorStatus(EINVAL);
-  }
-
-  if (is_full()) {
-    ALOGE("ProducerQueue::AllocateBuffer queue is at maximum capacity: %zu",
-          capacity());
+Status<std::vector<size_t>> ProducerQueue::AllocateBuffers(
+    uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+    uint64_t usage, size_t buffer_count) {
+  if (capacity() + buffer_count > kMaxQueueCapacity) {
+    ALOGE(
+        "ProducerQueue::AllocateBuffers: queue is at capacity: %zu, cannot "
+        "allocate %zu more buffer(s).",
+        capacity(), buffer_count);
     return ErrorStatus(E2BIG);
   }
 
-  const size_t kBufferCount = 1u;
   Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status =
       InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>(
-          width, height, layer_count, format, usage, kBufferCount);
+          width, height, layer_count, format, usage, buffer_count);
   if (!status) {
-    ALOGE("ProducerQueue::AllocateBuffer failed to create producer buffer: %s",
+    ALOGE("ProducerQueue::AllocateBuffers: failed to allocate buffers: %s",
           status.GetErrorMessage().c_str());
     return status.error_status();
   }
 
   auto buffer_handle_slots = status.take();
-  LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != kBufferCount,
+  LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != buffer_count,
                       "BufferHubRPC::ProducerQueueAllocateBuffers should "
-                      "return one and only one buffer handle.");
+                      "return %zu buffer handle(s), but returned %zu instead.",
+                      buffer_count, buffer_handle_slots.size());
 
+  std::vector<size_t> buffer_slots;
+  buffer_slots.reserve(buffer_count);
+
+  // Bookkeeping for each buffer.
+  for (auto& hs : buffer_handle_slots) {
+    auto& buffer_handle = hs.first;
+    size_t buffer_slot = hs.second;
+
+    // Note that import might (though very unlikely) fail. If so, buffer_handle
+    // will be closed and included in returned buffer_slots.
+    if (AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
+                  buffer_slot)) {
+      ALOGD_IF(TRACE, "ProducerQueue::AllocateBuffers: new buffer at slot: %zu",
+               buffer_slot);
+      buffer_slots.push_back(buffer_slot);
+    }
+  }
+
+  if (buffer_slots.size() == 0) {
+    // Error out if no buffer is allocated and improted.
+    ALOGE(TRACE, "ProducerQueue::AllocateBuffers: no buffer allocated.");
+    ErrorStatus(ENOMEM);
+  }
+
+  return {std::move(buffer_slots)};
+}
+
+Status<size_t> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
+                                             uint32_t layer_count,
+                                             uint32_t format, uint64_t usage) {
   // We only allocate one buffer at a time.
-  auto& buffer_handle = buffer_handle_slots[0].first;
-  size_t buffer_slot = buffer_handle_slots[0].second;
-  ALOGD_IF(TRACE,
-           "ProducerQueue::AllocateBuffer, new buffer, channel_handle: %d",
-           buffer_handle.value());
+  constexpr size_t buffer_count = 1;
+  auto status =
+      AllocateBuffers(width, height, layer_count, format, usage, buffer_count);
+  if (!status) {
+    ALOGE("ProducerQueue::AllocateBuffer: Failed to allocate buffer: %s",
+          status.GetErrorMessage().c_str());
+    return status.error_status();
+  }
 
-  *out_slot = buffer_slot;
-  return AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
-                   buffer_slot);
+  if (status.get().size() == 0) {
+    ALOGE(TRACE, "ProducerQueue::AllocateBuffer: no buffer allocated.");
+    ErrorStatus(ENOMEM);
+  }
+
+  return {status.get()[0]};
 }
 
 Status<void> ProducerQueue::AddBuffer(
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index fca5eca..0f75a5c 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -612,9 +612,8 @@
                                                 uint32_t layer_count,
                                                 PixelFormat format,
                                                 uint64_t usage) {
-  size_t slot;
   auto status =
-      queue_->AllocateBuffer(width, height, layer_count, format, usage, &slot);
+      queue_->AllocateBuffer(width, height, layer_count, format, usage);
   if (!status) {
     ALOGE(
         "BufferHubQueueProducer::AllocateBuffer: Failed to allocate buffer: %s",
@@ -622,6 +621,7 @@
     return NO_MEMORY;
   }
 
+  size_t slot = status.get();
   auto buffer_producer = queue_->GetBuffer(slot);
 
   LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr,
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index 912cee0..d57c7af 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -274,12 +274,20 @@
         BufferHubQueue::GetBuffer(slot));
   }
 
+  // Batch allocate buffers. Once allocated, producer buffers are automatically
+  // enqueue'd into the ProducerQueue and available to use (i.e. in GAINED
+  // state). Upon success, returns a list of slots for each buffer allocated.
+  pdx::Status<std::vector<size_t>> AllocateBuffers(
+      uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+      uint64_t usage, size_t buffer_count);
+
   // Allocate producer buffer to populate the queue. Once allocated, a producer
   // buffer is automatically enqueue'd into the ProducerQueue and available to
-  // use (i.e. in GAINED state).
-  pdx::Status<void> AllocateBuffer(uint32_t width, uint32_t height,
-                                   uint32_t layer_count, uint32_t format,
-                                   uint64_t usage, size_t* out_slot);
+  // use (i.e. in GAINED state). Upon success, returns the slot number for the
+  // buffer allocated.
+  pdx::Status<size_t> AllocateBuffer(uint32_t width, uint32_t height,
+                                     uint32_t layer_count, uint32_t format,
+                                     uint64_t usage);
 
   // Add a producer buffer to populate the queue. Once added, a producer buffer
   // is available to use (i.e. in GAINED state).
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 228212e..e0a4052 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -46,12 +46,12 @@
 
   void AllocateBuffer(size_t* slot_out = nullptr) {
     // Create producer buffer.
-    size_t slot;
     auto status = producer_queue_->AllocateBuffer(
         kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-        kBufferUsage, &slot);
-    ASSERT_TRUE(status.ok());
+        kBufferUsage);
 
+    ASSERT_TRUE(status.ok());
+    size_t slot = status.take();
     if (slot_out)
       *slot_out = slot;
   }
@@ -478,13 +478,13 @@
                            UsagePolicy{set_mask, 0, 0, 0}));
 
   // When allocation, leave out |set_mask| from usage bits on purpose.
-  size_t slot;
   auto status = producer_queue_->AllocateBuffer(
       kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage & ~set_mask, &slot);
+      kBufferUsage & ~set_mask);
   ASSERT_TRUE(status.ok());
 
   LocalHandle fence;
+  size_t slot;
   auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
@@ -497,13 +497,13 @@
                            UsagePolicy{0, clear_mask, 0, 0}));
 
   // When allocation, add |clear_mask| into usage bits on purpose.
-  size_t slot;
   auto status = producer_queue_->AllocateBuffer(
       kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage | clear_mask, &slot);
+      kBufferUsage | clear_mask);
   ASSERT_TRUE(status.ok());
 
   LocalHandle fence;
+  size_t slot;
   auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
@@ -517,16 +517,15 @@
 
   // Now that |deny_set_mask| is illegal, allocation without those bits should
   // be able to succeed.
-  size_t slot;
   auto status = producer_queue_->AllocateBuffer(
       kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage & ~deny_set_mask, &slot);
+      kBufferUsage & ~deny_set_mask);
   ASSERT_TRUE(status.ok());
 
   // While allocation with those bits should fail.
   status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
                                            kBufferLayerCount, kBufferFormat,
-                                           kBufferUsage | deny_set_mask, &slot);
+                                           kBufferUsage | deny_set_mask);
   ASSERT_FALSE(status.ok());
   ASSERT_EQ(EINVAL, status.error());
 }
@@ -538,16 +537,15 @@
 
   // Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are
   // mandatory), allocation with those bits should be able to succeed.
-  size_t slot;
   auto status = producer_queue_->AllocateBuffer(
       kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage | deny_clear_mask, &slot);
+      kBufferUsage | deny_clear_mask);
   ASSERT_TRUE(status.ok());
 
   // While allocation without those bits should fail.
   status = producer_queue_->AllocateBuffer(
       kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage & ~deny_clear_mask, &slot);
+      kBufferUsage & ~deny_clear_mask);
   ASSERT_FALSE(status.ok());
   ASSERT_EQ(EINVAL, status.error());
 }
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 6e7f556..442c82d 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -104,10 +104,8 @@
   return {};
 }
 
-Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(uint32_t width,
-                                                            uint32_t height,
-                                                            uint32_t format,
-                                                            size_t metadata_size) {
+Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
+    uint32_t width, uint32_t height, uint32_t format, size_t metadata_size) {
   ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue.");
   auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(
       ProducerQueueConfigBuilder()
@@ -145,20 +143,12 @@
   auto producer_queue = status.take();
 
   ALOGD_IF(TRACE, "Surface::CreateQueue: Allocating %zu buffers...", capacity);
-  for (size_t i = 0; i < capacity; i++) {
-    size_t slot;
-    auto allocate_status = producer_queue->AllocateBuffer(
-        width, height, layer_count, format, usage, &slot);
-    if (!allocate_status) {
-      ALOGE(
-          "Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
+  auto allocate_status = producer_queue->AllocateBuffers(
+      width, height, layer_count, format, usage, capacity);
+  if (!allocate_status) {
+    ALOGE("Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
           producer_queue->id(), allocate_status.GetErrorMessage().c_str());
-      return allocate_status.error_status();
-    }
-    ALOGD_IF(
-        TRACE,
-        "Surface::CreateQueue: Allocated buffer at slot=%zu of capacity=%zu",
-        slot, capacity);
+    return allocate_status.error_status();
   }
 
   return {std::move(producer_queue)};
@@ -198,6 +188,42 @@
     return ErrorStatus(error);
 }
 
+pdx::Status<std::unique_ptr<IonBuffer>> DisplayClient::SetupGlobalBuffer(
+    DvrGlobalBufferKey key, size_t size, uint64_t usage) {
+  auto status =
+      InvokeRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(key, size, usage);
+  if (!status) {
+    ALOGE(
+        "DisplayClient::SetupGlobalBuffer: Failed to create the global buffer "
+        "%s",
+        status.GetErrorMessage().c_str());
+    return status.error_status();
+  }
+
+  auto ion_buffer = std::make_unique<IonBuffer>();
+  auto native_buffer_handle = status.take();
+  const int ret = native_buffer_handle.Import(ion_buffer.get());
+  if (ret < 0) {
+    ALOGE(
+        "DisplayClient::GetGlobalBuffer: Failed to import global buffer: "
+        "key=%d; error=%s",
+        key, strerror(-ret));
+    return ErrorStatus(-ret);
+  }
+
+  return {std::move(ion_buffer)};
+}
+
+pdx::Status<void> DisplayClient::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
+  auto status = InvokeRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(key);
+  if (!status) {
+    ALOGE("DisplayClient::DeleteGlobalBuffer Failed: %s",
+          status.GetErrorMessage().c_str());
+  }
+
+  return status;
+}
+
 Status<std::unique_ptr<IonBuffer>> DisplayClient::GetGlobalBuffer(
     DvrGlobalBufferKey key) {
   auto status = InvokeRemoteMethod<DisplayProtocol::GetGlobalBuffer>(key);
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
index 098b725..974c231 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdisplay/display_manager_client.cpp
@@ -32,44 +32,6 @@
   return status;
 }
 
-pdx::Status<std::unique_ptr<IonBuffer>> DisplayManagerClient::SetupGlobalBuffer(
-    DvrGlobalBufferKey key, size_t size, uint64_t usage) {
-  auto status = InvokeRemoteMethod<DisplayManagerProtocol::SetupGlobalBuffer>(
-      key, size, usage);
-  if (!status) {
-    ALOGE(
-        "DisplayManagerClient::SetupGlobalBuffer: Failed to create the global "
-        "buffer %s",
-        status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  auto ion_buffer = std::make_unique<IonBuffer>();
-  auto native_buffer_handle = status.take();
-  const int ret = native_buffer_handle.Import(ion_buffer.get());
-  if (ret < 0) {
-    ALOGE(
-        "DisplayManagerClient::GetGlobalBuffer: Failed to import global "
-        "buffer: key=%d; error=%s",
-        key, strerror(-ret));
-    return ErrorStatus(-ret);
-  }
-
-  return {std::move(ion_buffer)};
-}
-
-pdx::Status<void> DisplayManagerClient::DeleteGlobalBuffer(
-    DvrGlobalBufferKey key) {
-  auto status =
-      InvokeRemoteMethod<DisplayManagerProtocol::DeleteGlobalBuffer>(key);
-  if (!status) {
-    ALOGE("DisplayManagerClient::DeleteGlobalBuffer Failed: %s",
-          status.GetErrorMessage().c_str());
-  }
-
-  return status;
-}
-
 pdx::Status<std::unique_ptr<ConsumerQueue>>
 DisplayManagerClient::GetSurfaceQueue(int surface_id, int queue_id) {
   auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceQueue>(
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index b25adc4..caf3182 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -73,6 +73,9 @@
  public:
   pdx::Status<Metrics> GetDisplayMetrics();
   pdx::Status<std::string> GetConfigurationData(ConfigFileType config_type);
+  pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer(
+      DvrGlobalBufferKey key, size_t size, uint64_t usage);
+  pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
   pdx::Status<std::unique_ptr<IonBuffer>> GetGlobalBuffer(
       DvrGlobalBufferKey key);
   pdx::Status<std::unique_ptr<Surface>> CreateSurface(
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 7281b76..45aef51 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
@@ -21,9 +21,6 @@
   ~DisplayManagerClient() override;
 
   pdx::Status<std::vector<SurfaceState>> GetSurfaceState();
-  pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer(
-      DvrGlobalBufferKey key, size_t size, uint64_t usage);
-  pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
   pdx::Status<std::unique_ptr<ConsumerQueue>> GetSurfaceQueue(int surface_id,
                                                               int queue_id);
 
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index 5b23632..eff50ba 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -200,6 +200,8 @@
   enum {
     kOpGetMetrics = 0,
     kOpGetConfigurationData,
+    kOpSetupGlobalBuffer,
+    kOpDeleteGlobalBuffer,
     kOpGetGlobalBuffer,
     kOpIsVrAppRunning,
     kOpCreateSurface,
@@ -216,6 +218,11 @@
   PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void));
   PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData,
                     std::string(ConfigFileType config_type));
+  PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer,
+                    LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size,
+                                            uint64_t usage));
+  PDX_REMOTE_METHOD(DeleteGlobalBuffer, kOpDeleteGlobalBuffer,
+                    void(DvrGlobalBufferKey key));
   PDX_REMOTE_METHOD(GetGlobalBuffer, kOpGetGlobalBuffer,
                     LocalNativeBufferHandle(DvrGlobalBufferKey key));
   PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, bool(Void));
@@ -237,8 +244,6 @@
   enum {
     kOpGetSurfaceState = 0,
     kOpGetSurfaceQueue,
-    kOpSetupGlobalBuffer,
-    kOpDeleteGlobalBuffer,
   };
 
   // Aliases.
@@ -250,11 +255,6 @@
                     std::vector<SurfaceState>(Void));
   PDX_REMOTE_METHOD(GetSurfaceQueue, kOpGetSurfaceQueue,
                     LocalChannelHandle(int surface_id, int queue_id));
-  PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer,
-                    LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size,
-                                            uint64_t usage));
-  PDX_REMOTE_METHOD(DeleteGlobalBuffer, kOpDeleteGlobalBuffer,
-                    void(DvrGlobalBufferKey key));
 };
 
 struct VSyncSchedInfo {
diff --git a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
index ed06515..20541a6 100644
--- a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
+++ b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
@@ -103,9 +103,14 @@
   // Try obtaining the ring. If the named buffer has not been created yet, it
   // will return nullptr.
   RingType* Ring() {
-    if (IsMapped() == false) {
-      TryMapping();
+    // No ring created yet?
+    if (ring_ == nullptr) {
+      // Not mapped the memory yet?
+      if (IsMapped() == false) {
+        TryMapping();
+      }
 
+      // If have the memory mapped, allocate the ring.
       if (IsMapped()) {
         switch (usage_mode_) {
           case CPUUsageMode::READ_OFTEN:
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index 5f35dcf..dc31917 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -3,6 +3,8 @@
 #include <errno.h>
 #include <utils/Log.h>
 
+#include <algorithm>
+
 // Headers from libdvr
 #include <dvr/dvr_buffer.h>
 #include <dvr/dvr_buffer_queue.h>
@@ -23,15 +25,20 @@
   ALOGI("dvrGetApi: api=%p struct_size=%zu version=%d", api, struct_size,
         version);
   if (version == 1) {
-    if (struct_size != sizeof(DvrApi_v1)) {
-      ALOGE("dvrGetApi: Size mismatch: expected %zu; actual %zu",
-            sizeof(DvrApi_v1), struct_size);
-      return -EINVAL;
-    }
+    // New entry points are added at the end. If the caller's struct and
+    // this library have different sizes, we define the entry points in common.
+    // The caller is expected to handle unset entry points if necessary.
+    size_t clamped_struct_size = std::min(struct_size, sizeof(DvrApi_v1));
     DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api);
 
 // Defines an API entry for V1 (no version suffix).
-#define DVR_V1_API_ENTRY(name) dvr_api->name = dvr##name
+#define DVR_V1_API_ENTRY(name)                                 \
+  do {                                                         \
+    if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
+        clamped_struct_size) {                                 \
+      dvr_api->name = dvr##name;                               \
+    }                                                          \
+  } while (0)
 
 #include "include/dvr/dvr_api_entries.h"
 
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 5d01c8f..aa2ed94 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -122,7 +122,7 @@
     }
 
     auto allocate_status = producer_queue_->AllocateBuffer(
-        width_, height_, old_layer_count, format_, old_usage, &slot);
+        width_, height_, old_layer_count, format_, old_usage);
     if (!allocate_status) {
       ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s",
             allocate_status.GetErrorMessage().c_str());
diff --git a/libs/vr/libdvr/dvr_display_manager.cpp b/libs/vr/libdvr/dvr_display_manager.cpp
index 26973f9..852f9a4 100644
--- a/libs/vr/libdvr/dvr_display_manager.cpp
+++ b/libs/vr/libdvr/dvr_display_manager.cpp
@@ -2,7 +2,6 @@
 
 #include <dvr/dvr_buffer.h>
 #include <pdx/rpc/variant.h>
-#include <private/android/AHardwareBufferHelpers.h>
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/buffer_hub_queue_client.h>
 #include <private/dvr/display_client.h>
@@ -11,7 +10,6 @@
 #include "dvr_internal.h"
 #include "dvr_buffer_queue_internal.h"
 
-using android::AHardwareBuffer_convertToGrallocUsageBits;
 using android::dvr::BufferConsumer;
 using android::dvr::display::DisplayManagerClient;
 using android::dvr::display::SurfaceAttributes;
@@ -112,44 +110,6 @@
 
 void dvrDisplayManagerDestroy(DvrDisplayManager* client) { delete client; }
 
-int dvrDisplayManagerSetupGlobalBuffer(DvrDisplayManager* client,
-                                       DvrGlobalBufferKey key, size_t size,
-                                       uint64_t usage, DvrBuffer** buffer_out) {
-  if (!client || !buffer_out)
-    return -EINVAL;
-
-  uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
-
-  auto buffer_status =
-      client->client->SetupGlobalBuffer(key, size, gralloc_usage);
-  if (!buffer_status) {
-    ALOGE(
-        "dvrDisplayManagerSetupGlobalBuffer: Failed to setup global buffer: %s",
-        buffer_status.GetErrorMessage().c_str());
-    return -buffer_status.error();
-  }
-
-  *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take());
-  return 0;
-}
-
-int dvrDisplayManagerDeleteGlobalBuffer(DvrDisplayManager* client,
-                                        DvrGlobalBufferKey key) {
-  if (!client)
-    return -EINVAL;
-
-  auto buffer_status = client->client->DeleteGlobalBuffer(key);
-  if (!buffer_status) {
-    ALOGE(
-        "dvrDisplayManagerDeleteGlobalBuffer: Failed to delete named buffer: "
-        "%s",
-        buffer_status.GetErrorMessage().c_str());
-    return -buffer_status.error();
-  }
-
-  return 0;
-}
-
 int dvrDisplayManagerGetEventFd(DvrDisplayManager* client) {
   if (!client)
     return -EINVAL;
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
index b7c127a..c44f8a6 100644
--- a/libs/vr/libdvr/dvr_surface.cpp
+++ b/libs/vr/libdvr/dvr_surface.cpp
@@ -2,11 +2,13 @@
 
 #include <inttypes.h>
 
+#include <private/android/AHardwareBufferHelpers.h>
 #include <private/dvr/display_client.h>
 
-#include "dvr_internal.h"
 #include "dvr_buffer_queue_internal.h"
+#include "dvr_internal.h"
 
+using android::AHardwareBuffer_convertToGrallocUsageBits;
 using android::dvr::display::DisplayClient;
 using android::dvr::display::Surface;
 using android::dvr::display::SurfaceAttributes;
@@ -144,8 +146,8 @@
     return -EINVAL;
   }
 
-  auto status = surface->surface->CreateQueue(width, height, layer_count,
-                                              format, usage, capacity, metadata_size);
+  auto status = surface->surface->CreateQueue(
+      width, height, layer_count, format, usage, capacity, metadata_size);
   if (!status) {
     ALOGE("dvrSurfaceCreateWriteBufferQueue: Failed to create queue: %s",
           status.GetErrorMessage().c_str());
@@ -156,17 +158,61 @@
   return 0;
 }
 
-int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer) {
-  auto client = DisplayClient::Create();
+int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage,
+                         DvrBuffer** buffer_out) {
+  if (!buffer_out)
+    return -EINVAL;
+
+  int error;
+  auto client = DisplayClient::Create(&error);
   if (!client) {
-    ALOGE("dvrGetGlobalBuffer: Failed to create display client!");
-    return -ECOMM;
+    ALOGE("dvrSetupGlobalBuffer: Failed to create display client: %s",
+          strerror(-error));
+    return error;
   }
 
-  if (out_buffer == nullptr) {
-    ALOGE("dvrGetGlobalBuffer: Invalid inputs: key=%d, out_buffer=%p.", key,
-          out_buffer);
+  uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
+
+  auto buffer_status = client->SetupGlobalBuffer(key, size, gralloc_usage);
+  if (!buffer_status) {
+    ALOGE("dvrSetupGlobalBuffer: Failed to setup global buffer: %s",
+          buffer_status.GetErrorMessage().c_str());
+    return -buffer_status.error();
+  }
+
+  *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take());
+  return 0;
+}
+
+int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key) {
+  int error;
+  auto client = DisplayClient::Create(&error);
+  if (!client) {
+    ALOGE("dvrDeleteGlobalBuffer: Failed to create display client: %s",
+          strerror(-error));
+    return error;
+  }
+
+  auto buffer_status = client->DeleteGlobalBuffer(key);
+  if (!buffer_status) {
+    ALOGE("dvrDeleteGlobalBuffer: Failed to delete named buffer: %s",
+          buffer_status.GetErrorMessage().c_str());
+    return -buffer_status.error();
+  }
+
+  return 0;
+}
+
+int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer) {
+  if (!out_buffer)
     return -EINVAL;
+
+  int error;
+  auto client = DisplayClient::Create(&error);
+  if (!client) {
+    ALOGE("dvrGetGlobalBuffer: Failed to create display client: %s",
+          strerror(-error));
+    return error;
   }
 
   auto status = client->GetGlobalBuffer(key);
@@ -177,4 +223,38 @@
   return 0;
 }
 
+int dvrGetNativeDisplayMetrics(size_t sizeof_metrics,
+                               DvrNativeDisplayMetrics* metrics) {
+  ALOGE_IF(sizeof_metrics != sizeof(DvrNativeDisplayMetrics),
+           "dvrGetNativeDisplayMetrics: metrics struct mismatch, your dvr api "
+           "header is out of date.");
+
+  auto client = DisplayClient::Create();
+  if (!client) {
+    ALOGE("dvrGetNativeDisplayMetrics: Failed to create display client!");
+    return -ECOMM;
+  }
+
+  if (metrics == nullptr) {
+    ALOGE("dvrGetNativeDisplayMetrics: output metrics buffer must be non-null");
+    return -EINVAL;
+  }
+
+  auto status = client->GetDisplayMetrics();
+
+  if (!status) {
+    return -status.error();
+  }
+
+  if (sizeof_metrics >= 20) {
+    metrics->display_width = status.get().display_width;
+    metrics->display_height = status.get().display_height;
+    metrics->display_x_dpi = status.get().display_x_dpi;
+    metrics->display_y_dpi = status.get().display_y_dpi;
+    metrics->vsync_period_ns = status.get().vsync_period_ns;
+  }
+
+  return 0;
+}
+
 }  // extern "C"
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 0c10907..4b530b2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -41,6 +41,19 @@
 typedef struct DvrSurfaceAttributeValue DvrSurfaceAttributeValue;
 typedef struct DvrSurfaceAttribute DvrSurfaceAttribute;
 
+// Note: To avoid breaking others during active development, only modify this
+// struct by appending elements to the end.
+// If you do feel we should to re-arrange or remove elements, please make a
+// note of it, and wait until we're about to finalize for an API release to do
+// so.
+typedef struct DvrNativeDisplayMetrics {
+  uint32_t display_width;
+  uint32_t display_height;
+  uint32_t display_x_dpi;
+  uint32_t display_y_dpi;
+  uint32_t vsync_period_ns;
+} DvrNativeDisplayMetrics;
+
 // native_handle contains the fds for the underlying ION allocations inside
 // the gralloc buffer. This is needed temporarily while GPU vendors work on
 // better support for AHardwareBuffer via glBindSharedBuffer APIs. See
@@ -61,11 +74,6 @@
 // dvr_display_manager.h
 typedef int (*DvrDisplayManagerCreatePtr)(DvrDisplayManager** client_out);
 typedef void (*DvrDisplayManagerDestroyPtr)(DvrDisplayManager* client);
-typedef int (*DvrDisplayManagerSetupGlobalBufferPtr)(DvrDisplayManager* client,
-                                                     DvrGlobalBufferKey key,
-                                                     size_t size,
-                                                     uint64_t usage,
-                                                     DvrBuffer** buffer_out);
 typedef int (*DvrDisplayManagerGetEventFdPtr)(DvrDisplayManager* client);
 typedef int (*DvrDisplayManagerTranslateEpollEventMaskPtr)(
     DvrDisplayManager* client, int in_events, int* out_events);
@@ -188,6 +196,9 @@
     DvrReadBufferQueue* read_queue);
 
 // dvr_surface.h
+typedef int (*DvrSetupGlobalBufferPtr)(DvrGlobalBufferKey key, size_t size,
+                                       uint64_t usage, DvrBuffer** buffer_out);
+typedef int (*DvrDeleteGlobalBufferPtr)(DvrGlobalBufferKey key);
 typedef int (*DvrGetGlobalBufferPtr)(DvrGlobalBufferKey key,
                                      DvrBuffer** out_buffer);
 typedef int (*DvrSurfaceCreatePtr)(const DvrSurfaceAttribute* attributes,
@@ -202,6 +213,8 @@
     DvrSurface* surface, uint32_t width, uint32_t height, uint32_t format,
     uint32_t layer_count, uint64_t usage, size_t capacity, size_t metadata_size,
     DvrWriteBufferQueue** queue_out);
+typedef int (*DvrGetNativeDisplayMetricsPtr)(size_t sizeof_metrics,
+                                             DvrNativeDisplayMetrics* metrics);
 
 // dvr_vsync.h
 typedef int (*DvrVSyncClientCreatePtr)(DvrVSyncClient** client_out);
@@ -238,6 +251,8 @@
                                           float pressure);
 typedef int (*DvrVirtualTouchpadButtonStatePtr)(DvrVirtualTouchpad* client,
                                                 int touchpad, int buttons);
+typedef int (*DvrVirtualTouchpadScrollPtr)(DvrVirtualTouchpad* client,
+                                           int touchpad, float x, float y);
 
 // dvr_hardware_composer_client.h
 typedef struct DvrHwcClient DvrHwcClient;
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index 802a0f7..64e5e71 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -12,7 +12,6 @@
 // Display manager client
 DVR_V1_API_ENTRY(DisplayManagerCreate);
 DVR_V1_API_ENTRY(DisplayManagerDestroy);
-DVR_V1_API_ENTRY(DisplayManagerSetupGlobalBuffer);
 DVR_V1_API_ENTRY(DisplayManagerGetEventFd);
 DVR_V1_API_ENTRY(DisplayManagerTranslateEpollEventMask);
 DVR_V1_API_ENTRY(DisplayManagerGetSurfaceState);
@@ -92,6 +91,8 @@
 DVR_V1_API_ENTRY(SurfaceGetId);
 DVR_V1_API_ENTRY(SurfaceSetAttributes);
 DVR_V1_API_ENTRY(SurfaceCreateWriteBufferQueue);
+DVR_V1_API_ENTRY(SetupGlobalBuffer);
+DVR_V1_API_ENTRY(DeleteGlobalBuffer);
 DVR_V1_API_ENTRY(GetGlobalBuffer);
 
 // Pose client
@@ -141,3 +142,12 @@
 DVR_V1_API_ENTRY(HwcFrameGetLayerVisibleRegion);
 DVR_V1_API_ENTRY(HwcFrameGetLayerNumDamagedRegions);
 DVR_V1_API_ENTRY(HwcFrameGetLayerDamagedRegion);
+
+// New entries added at the end to allow the DVR platform library API
+// to be updated before updating VrCore.
+
+// Virtual touchpad client
+DVR_V1_API_ENTRY(VirtualTouchpadScroll);
+
+// Read the native display metrics from the hardware composer
+DVR_V1_API_ENTRY(GetNativeDisplayMetrics);
diff --git a/libs/vr/libdvr/include/dvr/dvr_display_manager.h b/libs/vr/libdvr/include/dvr/dvr_display_manager.h
index 26f85a0..f910d61 100644
--- a/libs/vr/libdvr/include/dvr/dvr_display_manager.h
+++ b/libs/vr/libdvr/include/dvr/dvr_display_manager.h
@@ -25,21 +25,6 @@
 // Destroys the display manager client object.
 void dvrDisplayManagerDestroy(DvrDisplayManager* client);
 
-// Sets up a named buffer for shared memory data transfer between display
-// clients and the display manager.
-// @return 0 on success. Otherwise returns a negative error value.
-int dvrDisplayManagerSetupGlobalBuffer(DvrDisplayManager* client,
-                                       DvrGlobalBufferKey key, size_t size,
-                                       uint64_t usage, DvrBuffer** buffer_out);
-
-// Deletes a named buffer. WARNING: This is dangerous because any existing
-// clients of this buffer will not be notified and will remain attached to
-// the old buffer. This is useful for tests, but probably not for production
-// code.
-// @return 0 on success. Otherwise returns a negative error value.
-int dvrDisplayManagerDeleteGlobalBuffer(DvrDisplayManager* client,
-                                        DvrGlobalBufferKey key);
-
 // Returns an fd used to signal when surface updates occur. Note that depending
 // on the underlying transport, only a subset of the real event bits may be
 // supported. Use dvrDisplayManagerClientTranslateEpollEventMask to get the real
diff --git a/libs/vr/libdvr/include/dvr/dvr_pose.h b/libs/vr/libdvr/include/dvr/dvr_pose.h
index a7e83c9..4256cf9 100644
--- a/libs/vr/libdvr/include/dvr/dvr_pose.h
+++ b/libs/vr/libdvr/include/dvr/dvr_pose.h
@@ -36,16 +36,23 @@
   int64_t timestamp_ns;
   // Bitmask of DVR_POSE_FLAG_* constants that apply to this pose.
   //
-  // If DVR_POSE_FLAG_VALID is not set, the pose is indeterminate.
+  // If DVR_POSE_FLAG_INVALID is set, the pose is indeterminate.
   uint64_t flags;
   // Reserved padding to 128 bytes.
   uint8_t pad[16];
 } DvrPoseAsync;
 
 enum {
-  DVR_POSE_FLAG_VALID = (1UL << 0),       // This pose is valid.
-  DVR_POSE_FLAG_HEAD = (1UL << 1),        // This pose is the head.
-  DVR_POSE_FLAG_CONTROLLER = (1UL << 2),  // This pose is a controller.
+  DVR_POSE_FLAG_INVALID = (1UL << 0),       // This pose is invalid.
+  DVR_POSE_FLAG_INITIALIZING = (1UL << 1),  // The pose delivered during
+                                            // initialization and it may not be
+                                            // correct.
+  DVR_POSE_FLAG_3DOF =
+      (1UL << 2),  // This pose is derived from 3Dof sensors. If
+                   // this is not set, pose is derived using
+                   // 3Dof and 6Dof sensors.
+  DVR_POSE_FLAG_FLOOR_HEIGHT_INVALID =
+      (1UL << 3),  // If set the floor height is invalid.
 };
 
 // Represents a sensor pose sample.
@@ -70,8 +77,14 @@
   // Timestamp for the measurement in nanoseconds.
   int64_t timestamp_ns;
 
-  // Padding to 96 bytes so the size is a multiple of 16.
-  uint8_t padding[8];
+  // The combination of flags above.
+  uint64_t flags;
+
+  // The current floor height. May be updated at a lower cadence than pose.
+  float floor_height;
+
+  // Padding to 112 bytes so the size is a multiple of 16.
+  uint8_t padding[12];
 } DvrPose;
 
 __END_DECLS
diff --git a/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h b/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h
index 096f800..63c7385 100644
--- a/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h
+++ b/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h
@@ -11,7 +11,7 @@
 namespace dvr {
 
 // Increment when the layout for the buffers change.
-enum : uint32_t { kSharedBufferLayoutVersion = 1 };
+enum : uint32_t { kSharedBufferLayoutVersion = 2 };
 
 // Note: These buffers will be mapped from various system processes as well
 // as VrCore and the application processes in a r/w manner.
@@ -24,7 +24,7 @@
 
 // Sanity check for basic type sizes.
 static_assert(sizeof(DvrPoseAsync) == 128, "Unexpected size for DvrPoseAsync");
-static_assert(sizeof(DvrPose) == 96, "Unexpected size for DvrPose");
+static_assert(sizeof(DvrPose) == 112, "Unexpected size for DvrPose");
 static_assert(sizeof(DvrVsync) == 32, "Unexpected size for DvrVsync");
 static_assert(sizeof(DvrConfig) == 16, "Unexpected size for DvrConfig");
 
@@ -85,7 +85,7 @@
   uint8_t padding[12];
 };
 
-static_assert(sizeof(DvrVsyncPoseBuffer) == 1136,
+static_assert(sizeof(DvrVsyncPoseBuffer) == 1152,
               "Unexpected size for DvrVsyncPoseBuffer");
 
 // The keys for the dvr global buffers.
diff --git a/libs/vr/libdvr/include/dvr/dvr_surface.h b/libs/vr/libdvr/include/dvr/dvr_surface.h
index ce1f435..74a68a1 100644
--- a/libs/vr/libdvr/include/dvr/dvr_surface.h
+++ b/libs/vr/libdvr/include/dvr/dvr_surface.h
@@ -79,10 +79,35 @@
                                      size_t capacity, size_t metadata_size,
                                      DvrWriteBufferQueue** queue_out);
 
+// Sets up a named buffer for shared memory data transfer between display
+// clients and the system. Protected API that may only be called with sufficient
+// privilege.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage,
+                         DvrBuffer** buffer_out);
+
+// Deletes a named buffer. WARNING: This is dangerous because any existing
+// clients of this buffer will not be notified and will remain attached to
+// the old buffer. This is useful for tests, but probably not for production
+// code.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key);
+
 // Get a global buffer from the display service.
 // @return 0 on success. Otherwise returns a negative error value.
 int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer);
 
+// Read the native device display metrics as reported by the hardware composer.
+// This is useful as otherwise the device metrics are only reported as
+// relative to the current device orientation.
+// @param sizeof_metrics the size of the passed in metrics struct. This is used
+//   to ensure we don't break each other during active development.
+// @param metrics on success holds the retrieved device metrics.
+// @return 0 on success. Otherwise returns a negative error value (typically
+//   this means the display service is not available).
+int dvrGetNativeDisplayMetrics(size_t metrics_struct_size,
+                               DvrNativeDisplayMetrics* metrics);
+
 __END_DECLS
 
 #endif  // ANDROID_DVR_SURFACE_H_
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index f2ae09e..5158612 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -56,13 +56,10 @@
   }
 
   void AllocateBuffers(size_t buffer_count) {
-    size_t out_slot;
-    for (size_t i = 0; i < buffer_count; i++) {
-      auto status = write_queue_->producer_queue()->AllocateBuffer(
-          kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
-          &out_slot);
-      ASSERT_TRUE(status.ok());
-    }
+    auto status = write_queue_->producer_queue()->AllocateBuffers(
+        kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
+        buffer_count);
+    ASSERT_TRUE(status.ok());
   }
 
   void HandleBufferAvailable() {
diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
index 566f9de..c21deb0 100644
--- a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
@@ -1,7 +1,6 @@
 #include <android/hardware_buffer.h>
 #include <dvr/dvr_buffer.h>
 #include <dvr/dvr_config.h>
-#include <dvr/dvr_display_manager.h>
 #include <dvr/dvr_shared_buffers.h>
 #include <dvr/dvr_surface.h>
 #include <system/graphics.h>
@@ -14,33 +13,15 @@
 
 namespace {
 
-class DvrGlobalBufferTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    const int ret = dvrDisplayManagerCreate(&client_);
-    ASSERT_EQ(0, ret);
-    ASSERT_NE(nullptr, client_);
-  }
-
-  void TearDown() override {
-    dvrDisplayManagerDestroy(client_);
-    client_ = nullptr;
-  }
-
-  DvrDisplayManager* client_ = nullptr;
-};
-
-TEST_F(DvrGlobalBufferTest, TestGlobalBuffersSameName) {
+TEST(DvrGlobalBufferTest, TestGlobalBuffersSameName) {
   const DvrGlobalBufferKey buffer_key = 101;
   DvrBuffer* buffer1 = nullptr;
-  int ret1 =
-      dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key, 10, 0, &buffer1);
+  int ret1 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer1);
   ASSERT_EQ(0, ret1);
   ASSERT_NE(nullptr, buffer1);
 
   DvrBuffer* buffer2 = nullptr;
-  int ret2 =
-      dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key, 10, 0, &buffer2);
+  int ret2 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer2);
   ASSERT_EQ(0, ret1);
   ASSERT_NE(nullptr, buffer2);
 
@@ -97,19 +78,17 @@
   AHardwareBuffer_release(hardware_buffer3);
 }
 
-TEST_F(DvrGlobalBufferTest, TestMultipleGlobalBuffers) {
+TEST(DvrGlobalBufferTest, TestMultipleGlobalBuffers) {
   const DvrGlobalBufferKey buffer_key1 = 102;
   const DvrGlobalBufferKey buffer_key2 = 103;
   DvrBuffer* setup_buffer1 = nullptr;
-  int ret1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key1, 10, 0,
-                                                &setup_buffer1);
+  int ret1 = dvrSetupGlobalBuffer(buffer_key1, 10, 0, &setup_buffer1);
   ASSERT_EQ(0, ret1);
   ASSERT_NE(nullptr, setup_buffer1);
   dvrBufferDestroy(setup_buffer1);
 
   DvrBuffer* setup_buffer2 = nullptr;
-  int ret2 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key2, 10, 0,
-                                                &setup_buffer2);
+  int ret2 = dvrSetupGlobalBuffer(buffer_key2, 10, 0, &setup_buffer2);
   ASSERT_EQ(0, ret2);
   ASSERT_NE(nullptr, setup_buffer2);
   dvrBufferDestroy(setup_buffer2);
@@ -127,7 +106,7 @@
   dvrBufferDestroy(buffer2);
 }
 
-TEST_F(DvrGlobalBufferTest, TestGlobalBufferUsage) {
+TEST(DvrGlobalBufferTest, TestGlobalBufferUsage) {
   const DvrGlobalBufferKey buffer_key = 100;
 
   // Set usage to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE. We use this because
@@ -138,8 +117,7 @@
   const uint64_t usage = AHARDWAREBUFFER_USAGE_VIDEO_ENCODE;
 
   DvrBuffer* setup_buffer = nullptr;
-  int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key, 10, usage,
-                                              &setup_buffer);
+  int e1 = dvrSetupGlobalBuffer(buffer_key, 10, usage, &setup_buffer);
   ASSERT_NE(nullptr, setup_buffer);
   ASSERT_EQ(0, e1);
 
@@ -156,7 +134,7 @@
   AHardwareBuffer_release(hardware_buffer);
 }
 
-TEST_F(DvrGlobalBufferTest, TestGlobalBufferCarriesData) {
+TEST(DvrGlobalBufferTest, TestGlobalBufferCarriesData) {
   const DvrGlobalBufferKey buffer_name = 110;
 
   uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
@@ -167,8 +145,7 @@
   {
     // Allocate some data and set it to something.
     DvrBuffer* setup_buffer = nullptr;
-    int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, size,
-                                                usage, &setup_buffer);
+    int e1 = dvrSetupGlobalBuffer(buffer_name, size, usage, &setup_buffer);
     ASSERT_NE(nullptr, setup_buffer);
     ASSERT_EQ(0, e1);
 
@@ -234,7 +211,7 @@
   }
 }
 
-TEST_F(DvrGlobalBufferTest, TestGlobalBufferZeroed) {
+TEST(DvrGlobalBufferTest, TestGlobalBufferZeroed) {
   const DvrGlobalBufferKey buffer_name = 120;
 
   // Allocate 1MB and check that it is all zeros.
@@ -242,8 +219,7 @@
                    AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
   constexpr size_t size = 1024 * 1024;
   DvrBuffer* setup_buffer = nullptr;
-  int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, size, usage,
-                                              &setup_buffer);
+  int e1 = dvrSetupGlobalBuffer(buffer_name, size, usage, &setup_buffer);
   ASSERT_NE(nullptr, setup_buffer);
   ASSERT_EQ(0, e1);
 
@@ -275,12 +251,12 @@
   AHardwareBuffer_release(hardware_buffer);
 }
 
-TEST_F(DvrGlobalBufferTest, TestVrflingerConfigBuffer) {
+TEST(DvrGlobalBufferTest, TestVrflingerConfigBuffer) {
   const DvrGlobalBufferKey buffer_name =
       DvrGlobalBuffers::kVrFlingerConfigBufferKey;
 
   // First delete any existing buffer so we can test the failure case.
-  dvrDisplayManagerDeleteGlobalBuffer(client_, buffer_name);
+  dvrDeleteGlobalBuffer(buffer_name);
 
   const uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
                          AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY;
@@ -290,14 +266,13 @@
 
   // Setup an invalid config buffer (too small) and assert that it fails.
   DvrBuffer* setup_buffer = nullptr;
-  int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, wrong_size,
-                                              usage, &setup_buffer);
+  int e1 = dvrSetupGlobalBuffer(buffer_name, wrong_size, usage, &setup_buffer);
   ASSERT_EQ(nullptr, setup_buffer);
   ASSERT_GT(0, e1);
 
   // Setup a correct config buffer.
-  int e2 = dvrDisplayManagerSetupGlobalBuffer(
-      client_, buffer_name, correct_size, usage, &setup_buffer);
+  int e2 =
+      dvrSetupGlobalBuffer(buffer_name, correct_size, usage, &setup_buffer);
   ASSERT_NE(nullptr, setup_buffer);
   ASSERT_EQ(0, e2);
 
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index f55e994..8fce140 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -5,12 +5,15 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        "-DLOG_TAG=\"libpdx\"",
+        "-DTRACE=0",
     ],
     export_include_dirs: ["private"],
     local_include_dirs: ["private"],
     srcs: [
         "client.cpp",
         "service.cpp",
+        "service_dispatcher.cpp",
         "status.cpp",
     ],
 }
diff --git a/libs/vr/libpdx/client.cpp b/libs/vr/libpdx/client.cpp
index bfa2d87..a01c4d6 100644
--- a/libs/vr/libpdx/client.cpp
+++ b/libs/vr/libpdx/client.cpp
@@ -1,6 +1,5 @@
 #include "pdx/client.h"
 
-#define LOG_TAG "ServiceFramework"
 #include <log/log.h>
 
 #include <pdx/trace.h>
diff --git a/libs/vr/libpdx/mock_tests.cpp b/libs/vr/libpdx/mock_tests.cpp
index 76fd154..4143837 100644
--- a/libs/vr/libpdx/mock_tests.cpp
+++ b/libs/vr/libpdx/mock_tests.cpp
@@ -3,7 +3,6 @@
 #include <pdx/mock_client_channel_factory.h>
 #include <pdx/mock_message_reader.h>
 #include <pdx/mock_message_writer.h>
-#include <pdx/mock_service_dispatcher.h>
 #include <pdx/mock_service_endpoint.h>
 
 TEST(MockTypes, Instantiation) {
@@ -15,6 +14,5 @@
   android::pdx::MockMessageReader message_reader;
   android::pdx::MockOutputResourceMapper output_resource_mapper;
   android::pdx::MockMessageWriter message_writer;
-  android::pdx::MockServiceDispatcher service_dispatcher;
   android::pdx::MockEndpoint endpoint;
 }
diff --git a/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h b/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h
deleted file mode 100644
index 9b51d30..0000000
--- a/libs/vr/libpdx/private/pdx/mock_service_dispatcher.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_
-
-#include <gmock/gmock.h>
-#include <pdx/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-
-class MockServiceDispatcher : public ServiceDispatcher {
- public:
-  MOCK_METHOD1(AddService, int(const std::shared_ptr<Service>& service));
-  MOCK_METHOD1(RemoveService, int(const std::shared_ptr<Service>& service));
-  MOCK_METHOD0(ReceiveAndDispatch, int());
-  MOCK_METHOD1(ReceiveAndDispatch, int(int timeout));
-  MOCK_METHOD0(EnterDispatchLoop, int());
-  MOCK_METHOD1(SetCanceled, void(bool cancel));
-  MOCK_CONST_METHOD0(IsCanceled, bool());
-};
-
-}  // namespace pdx
-}  // namespace android
-
-#endif  // ANDROID_PDX_MOCK_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
index e741d4a..7f829e7 100644
--- a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
+++ b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
@@ -66,6 +66,7 @@
   MOCK_METHOD0(AllocateMessageState, void*());
   MOCK_METHOD1(FreeMessageState, void(void* state));
   MOCK_METHOD0(Cancel, Status<void>());
+  MOCK_CONST_METHOD0(epoll_fd, int());
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/service_dispatcher.h b/libs/vr/libpdx/private/pdx/service_dispatcher.h
index c5e342a..bd27000 100644
--- a/libs/vr/libpdx/private/pdx/service_dispatcher.h
+++ b/libs/vr/libpdx/private/pdx/service_dispatcher.h
@@ -2,6 +2,11 @@
 #define ANDROID_PDX_SERVICE_DISPATCHER_H_
 
 #include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <pdx/file_handle.h>
 
 namespace android {
 namespace pdx {
@@ -15,7 +20,10 @@
  */
 class ServiceDispatcher {
  public:
-  virtual ~ServiceDispatcher() = default;
+  // Get a new instance of ServiceDispatcher, or return nullptr if init failed.
+  static std::unique_ptr<ServiceDispatcher> Create();
+
+  ~ServiceDispatcher();
 
   /*
    * Adds a service to the list of services handled by this dispatcher. This
@@ -24,7 +32,7 @@
    *
    * Returns 0 on success; -EEXIST if the service was already added.
    */
-  virtual int AddService(const std::shared_ptr<Service>& service) = 0;
+  int AddService(const std::shared_ptr<Service>& service);
 
   /*
    * Removes a service from this dispatcher. This will fail if any threads are
@@ -33,7 +41,7 @@
    * Returns 0 on success; -ENOENT if the service was not previously added;
    * -EBUSY if there are threads in the dispatcher.
    */
-  virtual int RemoveService(const std::shared_ptr<Service>& service) = 0;
+  int RemoveService(const std::shared_ptr<Service>& service);
 
   /*
    * Receive and dispatch one set of messages. Multiple threads may enter this
@@ -42,14 +50,14 @@
    * cycle, requiring an external loop. This is useful when other work needs
    * to be done in the service dispatch loop.
    */
-  virtual int ReceiveAndDispatch() = 0;
+  int ReceiveAndDispatch();
 
   /*
    * Same as above with timeout in milliseconds. A negative value means
    * infinite timeout, while a value of 0 means return immediately if no
    * messages are available to receive.
    */
-  virtual int ReceiveAndDispatch(int timeout) = 0;
+  int ReceiveAndDispatch(int timeout);
 
   /*
    * Receive and dispatch messages until canceled. When more than one thread
@@ -58,19 +66,39 @@
    * hands Message instances (via move assignment) over to a queue of threads
    * (or perhaps one of several) to handle.
    */
-  virtual int EnterDispatchLoop() = 0;
+  int EnterDispatchLoop();
 
   /*
    * Sets the canceled state of the dispatcher. When canceled is true, any
    * threads blocked waiting for messages will return. This method waits until
    * all dispatch threads have exited the dispatcher.
    */
-  virtual void SetCanceled(bool cancel) = 0;
+  void SetCanceled(bool cancel);
 
   /*
    * Gets the canceled state of the dispatcher.
    */
-  virtual bool IsCanceled() const = 0;
+  bool IsCanceled() const;
+
+ private:
+  ServiceDispatcher();
+
+  // Internal thread accounting.
+  int ThreadEnter();
+  void ThreadExit();
+
+  std::mutex mutex_;
+  std::condition_variable condition_;
+  std::atomic<bool> canceled_{false};
+
+  std::vector<std::shared_ptr<Service>> services_;
+
+  int thread_count_ = 0;
+  LocalHandle event_fd_;
+  LocalHandle epoll_fd_;
+
+  ServiceDispatcher(const ServiceDispatcher&) = delete;
+  void operator=(const ServiceDispatcher&) = delete;
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/service_endpoint.h b/libs/vr/libpdx/private/pdx/service_endpoint.h
index 28bd6bc..d581894 100644
--- a/libs/vr/libpdx/private/pdx/service_endpoint.h
+++ b/libs/vr/libpdx/private/pdx/service_endpoint.h
@@ -136,6 +136,10 @@
   // Cancels the endpoint, unblocking any receiver threads waiting for a
   // message.
   virtual Status<void> Cancel() = 0;
+
+  // Returns an fd that can be used with epoll() to wait for incoming messages
+  // from this endpoint.
+  virtual int epoll_fd() const = 0;
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index fab4770..1d3b62a 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -1,4 +1,3 @@
-#define LOG_TAG "ServiceFramework"
 #include "pdx/service.h"
 
 #include <fcntl.h>
@@ -10,8 +9,6 @@
 
 #include <pdx/trace.h>
 
-#define TRACE 0
-
 namespace android {
 namespace pdx {
 
diff --git a/libs/vr/libpdx_uds/service_dispatcher.cpp b/libs/vr/libpdx/service_dispatcher.cpp
similarity index 83%
rename from libs/vr/libpdx_uds/service_dispatcher.cpp
rename to libs/vr/libpdx/service_dispatcher.cpp
index 2c52578..b112fa3 100644
--- a/libs/vr/libpdx_uds/service_dispatcher.cpp
+++ b/libs/vr/libpdx/service_dispatcher.cpp
@@ -1,26 +1,25 @@
-#include "uds/service_dispatcher.h"
+#include <pdx/service_dispatcher.h>
 
 #include <errno.h>
 #include <log/log.h>
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
 
-#include "pdx/service.h"
-#include "uds/service_endpoint.h"
+#include <pdx/service.h>
+#include <pdx/service_endpoint.h>
 
 static const int kMaxEventsPerLoop = 128;
 
 namespace android {
 namespace pdx {
-namespace uds {
 
-std::unique_ptr<pdx::ServiceDispatcher> ServiceDispatcher::Create() {
+std::unique_ptr<ServiceDispatcher> ServiceDispatcher::Create() {
   std::unique_ptr<ServiceDispatcher> dispatcher{new ServiceDispatcher()};
   if (!dispatcher->epoll_fd_ || !dispatcher->event_fd_) {
     dispatcher.reset();
   }
 
-  return std::move(dispatcher);
+  return dispatcher;
 }
 
 ServiceDispatcher::ServiceDispatcher() {
@@ -70,18 +69,14 @@
 }
 
 int ServiceDispatcher::AddService(const std::shared_ptr<Service>& service) {
-  if (service->endpoint()->GetIpcTag() != Endpoint::kIpcTag)
-    return -EINVAL;
-
   std::lock_guard<std::mutex> autolock(mutex_);
 
-  auto* endpoint = static_cast<Endpoint*>(service->endpoint());
   epoll_event event;
   event.events = EPOLLIN;
   event.data.ptr = service.get();
 
-  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, endpoint->epoll_fd(), &event) <
-      0) {
+  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, service->endpoint()->epoll_fd(),
+                &event) < 0) {
     ALOGE("Failed to add service to dispatcher because: %s\n", strerror(errno));
     return -errno;
   }
@@ -91,9 +86,6 @@
 }
 
 int ServiceDispatcher::RemoveService(const std::shared_ptr<Service>& service) {
-  if (service->endpoint()->GetIpcTag() != Endpoint::kIpcTag)
-    return -EINVAL;
-
   std::lock_guard<std::mutex> autolock(mutex_);
 
   // It's dangerous to remove a service while other threads may be using it.
@@ -101,16 +93,15 @@
     return -EBUSY;
 
   epoll_event dummy;  // See BUGS in man 2 epoll_ctl.
-
-  auto* endpoint = static_cast<Endpoint*>(service->endpoint());
-  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, endpoint->epoll_fd(), &dummy) <
-      0) {
+  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, service->endpoint()->epoll_fd(),
+                &dummy) < 0) {
     ALOGE("Failed to remove service from dispatcher because: %s\n",
           strerror(errno));
     return -errno;
   }
 
-  services_.remove(service);
+  services_.erase(std::remove(services_.begin(), services_.end(), service),
+                  services_.end());
   return 0;
 }
 
@@ -139,7 +130,7 @@
       Service* service = static_cast<Service*>(events[i].data.ptr);
 
       ALOGI_IF(TRACE, "Dispatching message: fd=%d\n",
-               static_cast<Endpoint*>(service->endpoint())->epoll_fd());
+               service->endpoint()->epoll_fd());
       service->ReceiveAndDispatch();
     }
   }
@@ -171,7 +162,7 @@
         Service* service = static_cast<Service*>(events[i].data.ptr);
 
         ALOGI_IF(TRACE, "Dispatching message: fd=%d\n",
-                 static_cast<Endpoint*>(service->endpoint())->epoll_fd());
+                 service->endpoint()->epoll_fd());
         service->ReceiveAndDispatch();
       }
     }
@@ -197,6 +188,5 @@
 
 bool ServiceDispatcher::IsCanceled() const { return canceled_; }
 
-}  // namespace uds
 }  // namespace pdx
 }  // namespace android
diff --git a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h
deleted file mode 100644
index 158871c..0000000
--- a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/service_dispatcher.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_
-
-#include <servicefs/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-namespace default_transport {
-
-using ServiceDispatcher = ::android::pdx::servicefs::ServiceDispatcher;
-
-}  // namespace default_transport
-}  // namespace pdx
-}  // namespace android
-
-
-#endif  // ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h
deleted file mode 100644
index 7cb7a80..0000000
--- a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/service_dispatcher.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_
-
-#include <uds/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-namespace default_transport {
-
-using ServiceDispatcher = ::android::pdx::uds::ServiceDispatcher;
-
-}  // namespace default_transport
-}  // namespace pdx
-}  // namespace android
-
-
-#endif  // ANDROID_PDX_DEFAULT_TRANSPORT_UDS_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index 82a5ea7..d0b7cab 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -16,7 +16,6 @@
         "client_channel_factory.cpp",
         "client_channel.cpp",
         "ipc_helper.cpp",
-        "service_dispatcher.cpp",
         "service_endpoint.cpp",
     ],
     static_libs: [
diff --git a/libs/vr/libpdx_uds/client_channel_tests.cpp b/libs/vr/libpdx_uds/client_channel_tests.cpp
index 7c3c68a..1560030 100644
--- a/libs/vr/libpdx_uds/client_channel_tests.cpp
+++ b/libs/vr/libpdx_uds/client_channel_tests.cpp
@@ -13,6 +13,7 @@
 #include <pdx/client.h>
 #include <pdx/rpc/remote_method.h>
 #include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
 
 #include <uds/client_channel_factory.h>
 #include <uds/service_endpoint.h>
@@ -81,7 +82,7 @@
     auto endpoint = Endpoint::CreateFromSocketFd(LocalHandle{});
     endpoint->RegisterNewChannelForTests(std::move(channel_socket));
     service_ = TestService::Create(std::move(endpoint));
-    dispatcher_ = android::pdx::uds::ServiceDispatcher::Create();
+    dispatcher_ = ServiceDispatcher::Create();
     dispatcher_->AddService(service_);
     dispatch_thread_ = std::thread(
         std::bind(&ServiceDispatcher::EnterDispatchLoop, dispatcher_.get()));
diff --git a/libs/vr/libpdx_uds/private/uds/service_dispatcher.h b/libs/vr/libpdx_uds/private/uds/service_dispatcher.h
deleted file mode 100644
index 23af4f4..0000000
--- a/libs/vr/libpdx_uds/private/uds/service_dispatcher.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_
-#define ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_
-
-#include <list>
-#include <memory>
-#include <mutex>
-#include <unordered_map>
-
-#include <pdx/file_handle.h>
-#include <pdx/service_dispatcher.h>
-
-namespace android {
-namespace pdx {
-namespace uds {
-
-class ServiceDispatcher : public pdx::ServiceDispatcher {
- public:
-  // Get a new instance of ServiceDispatcher, or return nullptr if init failed.
-  static std::unique_ptr<pdx::ServiceDispatcher> Create();
-
-  ~ServiceDispatcher() override;
-  int AddService(const std::shared_ptr<Service>& service) override;
-  int RemoveService(const std::shared_ptr<Service>& service) override;
-  int ReceiveAndDispatch() override;
-  int ReceiveAndDispatch(int timeout) override;
-  int EnterDispatchLoop() override;
-  void SetCanceled(bool cancel) override;
-  bool IsCanceled() const override;
-
- private:
-  ServiceDispatcher();
-
-  // Internal thread accounting.
-  int ThreadEnter();
-  void ThreadExit();
-
-  std::mutex mutex_;
-  std::condition_variable condition_;
-  std::atomic<bool> canceled_{false};
-
-  std::list<std::shared_ptr<Service>> services_;
-
-  int thread_count_ = 0;
-  LocalHandle event_fd_;
-  LocalHandle epoll_fd_;
-
-  ServiceDispatcher(const ServiceDispatcher&) = delete;
-  void operator=(const ServiceDispatcher&) = delete;
-};
-
-}  // namespace uds
-}  // namespace pdx
-}  // namespace android
-
-#endif  // ANDROID_PDX_UDS_SERVICE_DISPATCHER_H_
diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
index 368891c..a163812 100644
--- a/libs/vr/libpdx_uds/private/uds/service_endpoint.h
+++ b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
@@ -12,7 +12,6 @@
 #include <pdx/service.h>
 #include <pdx/service_endpoint.h>
 #include <uds/channel_event_set.h>
-#include <uds/service_dispatcher.h>
 
 namespace android {
 namespace pdx {
@@ -105,7 +104,7 @@
   // socket file descriptor.
   Status<void> RegisterNewChannelForTests(LocalHandle channel_fd);
 
-  int epoll_fd() const { return epoll_fd_.Get(); }
+  int epoll_fd() const override { return epoll_fd_.Get(); }
 
  private:
   struct ChannelData {
diff --git a/libs/vr/libpdx_uds/remote_method_tests.cpp b/libs/vr/libpdx_uds/remote_method_tests.cpp
index 3109753..3f25776 100644
--- a/libs/vr/libpdx_uds/remote_method_tests.cpp
+++ b/libs/vr/libpdx_uds/remote_method_tests.cpp
@@ -15,9 +15,9 @@
 #include <pdx/rpc/remote_method.h>
 #include <pdx/rpc/serializable.h>
 #include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
 #include <uds/client_channel.h>
 #include <uds/client_channel_factory.h>
-#include <uds/service_dispatcher.h>
 #include <uds/service_endpoint.h>
 
 using android::pdx::BorrowedHandle;
@@ -561,7 +561,7 @@
 
   void SetUp() override {
     // Create a dispatcher to handle messages to services.
-    dispatcher_ = android::pdx::uds::ServiceDispatcher::Create();
+    dispatcher_ = android::pdx::ServiceDispatcher::Create();
     ASSERT_NE(nullptr, dispatcher_);
 
     // Start the message dispatch loop in a separate thread.
diff --git a/libs/vr/libpdx_uds/service_framework_tests.cpp b/libs/vr/libpdx_uds/service_framework_tests.cpp
index 2943239..5943b0a 100644
--- a/libs/vr/libpdx_uds/service_framework_tests.cpp
+++ b/libs/vr/libpdx_uds/service_framework_tests.cpp
@@ -16,10 +16,10 @@
 #include <pdx/client.h>
 #include <pdx/file_handle.h>
 #include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
 #include <private/android_filesystem_config.h>
 #include <uds/client_channel.h>
 #include <uds/client_channel_factory.h>
-#include <uds/service_dispatcher.h>
 #include <uds/service_endpoint.h>
 
 using android::pdx::BorrowedChannelHandle;
@@ -425,7 +425,7 @@
 
   void SetUp() override {
     // Create a dispatcher to handle messages to services.
-    dispatcher_ = android::pdx::uds::ServiceDispatcher::Create();
+    dispatcher_ = android::pdx::ServiceDispatcher::Create();
     ASSERT_NE(nullptr, dispatcher_);
 
     // Start the message dispatch loop in a separate thread.
diff --git a/libs/vr/libvrflinger/acquired_buffer.cpp b/libs/vr/libvrflinger/acquired_buffer.cpp
index 7932a9c..fda9585 100644
--- a/libs/vr/libvrflinger/acquired_buffer.cpp
+++ b/libs/vr/libvrflinger/acquired_buffer.cpp
@@ -55,9 +55,9 @@
   if (acquire_fence_) {
     const int ret = sync_wait(acquire_fence_.Get(), 0);
     ALOGD_IF(TRACE || (ret < 0 && errno != ETIME),
-             "AcquiredBuffer::IsAvailable: acquire_fence_=%d sync_wait()=%d "
-             "errno=%d.",
-             acquire_fence_.Get(), ret, ret < 0 ? errno : 0);
+             "AcquiredBuffer::IsAvailable: buffer_id=%d acquire_fence=%d "
+             "sync_wait()=%d errno=%d.",
+             buffer_->id(), acquire_fence_.Get(), ret, ret < 0 ? errno : 0);
     if (ret == 0) {
       // The fence is completed, so to avoid further calls to sync_wait we close
       // it here.
@@ -78,6 +78,8 @@
 }
 
 int AcquiredBuffer::Release(LocalHandle release_fence) {
+  ALOGD_IF(TRACE, "AcquiredBuffer::Release: buffer_id=%d release_fence=%d",
+           buffer_ ? buffer_->id() : -1, release_fence.Get());
   if (buffer_) {
     // Close the release fence since we can't transfer it with an async release.
     release_fence.Close();
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index dd4fcc5..e0dc9f2 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -67,13 +67,13 @@
   int Release(pdx::LocalHandle release_fence);
 
  private:
-  AcquiredBuffer(const AcquiredBuffer&) = delete;
-  void operator=(const AcquiredBuffer&) = delete;
-
   std::shared_ptr<BufferConsumer> buffer_;
   // Mutable so that the fence can be closed when it is determined to be
   // signaled during IsAvailable().
   mutable pdx::LocalHandle acquire_fence_;
+
+  AcquiredBuffer(const AcquiredBuffer&) = delete;
+  void operator=(const AcquiredBuffer&) = delete;
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index 0e9a6ab..40396b9 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -78,16 +78,6 @@
           *this, &DisplayManagerService::OnGetSurfaceQueue, message);
       return {};
 
-    case DisplayManagerProtocol::SetupGlobalBuffer::Opcode:
-      DispatchRemoteMethod<DisplayManagerProtocol::SetupGlobalBuffer>(
-          *this, &DisplayManagerService::OnSetupGlobalBuffer, message);
-      return {};
-
-    case DisplayManagerProtocol::DeleteGlobalBuffer::Opcode:
-      DispatchRemoteMethod<DisplayManagerProtocol::DeleteGlobalBuffer>(
-          *this, &DisplayManagerService::OnDeleteGlobalBuffer, message);
-      return {};
-
     default:
       return Service::DefaultHandleMessage(message);
   }
@@ -134,36 +124,6 @@
   return status;
 }
 
-pdx::Status<BorrowedNativeBufferHandle>
-DisplayManagerService::OnSetupGlobalBuffer(pdx::Message& message,
-                                           DvrGlobalBufferKey key, size_t size,
-                                           uint64_t usage) {
-  const int user_id = message.GetEffectiveUserId();
-  const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
-
-  if (!trusted) {
-    ALOGE(
-        "DisplayService::SetupGlobalBuffer: Global buffers may only be created "
-        "by trusted UIDs: user_id=%d",
-        user_id);
-    return ErrorStatus(EPERM);
-  }
-  return display_service_->SetupGlobalBuffer(key, size, usage);
-}
-
-pdx::Status<void> DisplayManagerService::OnDeleteGlobalBuffer(
-    pdx::Message& message, DvrGlobalBufferKey key) {
-  const int user_id = message.GetEffectiveUserId();
-  const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id);
-
-  if (!trusted) {
-    ALOGE("DisplayService::DeleteGlobalBuffer: Untrusted user_id (%d)",
-          user_id);
-    return ErrorStatus(EPERM);
-  }
-  return display_service_->DeleteGlobalBuffer(key);
-}
-
 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 c869ceb..3133fe1 100644
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ b/libs/vr/libvrflinger/display_manager_service.h
@@ -56,11 +56,6 @@
   pdx::Status<pdx::LocalChannelHandle> OnGetSurfaceQueue(pdx::Message& message,
                                                          int surface_id,
                                                          int queue_id);
-  pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer(
-      pdx::Message& message, DvrGlobalBufferKey key, size_t size,
-      uint64_t usage);
-  pdx::Status<void> OnDeleteGlobalBuffer(pdx::Message& message,
-                                         DvrGlobalBufferKey key);
 
   // Called by the display service to indicate changes to display surfaces that
   // the display manager should evaluate.
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index dc9807a..733edc6 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -1,6 +1,10 @@
 #include "display_service.h"
 
 #include <unistd.h>
+
+#include <algorithm>
+#include <sstream>
+#include <string>
 #include <vector>
 
 #include <android-base/file.h>
@@ -8,8 +12,10 @@
 #include <dvr/dvr_display_types.h>
 #include <pdx/default_transport/service_endpoint.h>
 #include <pdx/rpc/remote_method.h>
+#include <private/android_filesystem_config.h>
 #include <private/dvr/display_protocol.h>
 #include <private/dvr/numeric.h>
+#include <private/dvr/trusted_uids.h>
 #include <private/dvr/types.h>
 
 using android::dvr::display::DisplayProtocol;
@@ -45,7 +51,65 @@
 }
 
 std::string DisplayService::DumpState(size_t /*max_length*/) {
-  return hardware_composer_.Dump();
+  std::ostringstream stream;
+
+  auto surfaces = GetDisplaySurfaces();
+  std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
+    return a->surface_id() < b->surface_id();
+  });
+
+  stream << "Application Surfaces:" << std::endl;
+
+  size_t count = 0;
+  for (const auto& surface : surfaces) {
+    if (surface->surface_type() == SurfaceType::Application) {
+      stream << "Surface " << count++ << ":";
+      stream << " surface_id=" << surface->surface_id()
+             << " process_id=" << surface->process_id()
+             << " user_id=" << surface->user_id()
+             << " visible=" << surface->visible()
+             << " z_order=" << surface->z_order();
+
+      stream << " queue_ids=";
+      auto queue_ids = surface->GetQueueIds();
+      std::sort(queue_ids.begin(), queue_ids.end());
+      for (int32_t id : queue_ids) {
+        if (id != queue_ids[0])
+          stream << ",";
+        stream << id;
+      }
+      stream << std::endl;
+    }
+  }
+  stream << std::endl;
+
+  stream << "Direct Surfaces:" << std::endl;
+
+  count = 0;
+  for (const auto& surface : surfaces) {
+    if (surface->surface_type() == SurfaceType::Direct) {
+      stream << "Surface " << count++ << ":";
+      stream << " surface_id=" << surface->surface_id()
+             << " process_id=" << surface->process_id()
+             << " user_id=" << surface->user_id()
+             << " visible=" << surface->visible()
+             << " z_order=" << surface->z_order();
+
+      stream << " queue_ids=";
+      auto queue_ids = surface->GetQueueIds();
+      std::sort(queue_ids.begin(), queue_ids.end());
+      for (int32_t id : queue_ids) {
+        if (id != queue_ids[0])
+          stream << ",";
+        stream << id;
+      }
+      stream << std::endl;
+    }
+  }
+  stream << std::endl;
+
+  stream << hardware_composer_.Dump();
+  return stream.str();
 }
 
 void DisplayService::OnChannelClose(pdx::Message& message,
@@ -54,8 +118,6 @@
     surface->OnSetAttributes(message,
                              {{display::SurfaceAttribute::Visible,
                                display::SurfaceAttributeValue{false}}});
-    SurfaceUpdated(surface->surface_type(),
-                   display::SurfaceUpdateFlags::VisibilityChanged);
   }
 }
 
@@ -80,6 +142,16 @@
           *this, &DisplayService::OnCreateSurface, message);
       return {};
 
+    case DisplayProtocol::SetupGlobalBuffer::Opcode:
+      DispatchRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(
+          *this, &DisplayService::OnSetupGlobalBuffer, message);
+      return {};
+
+    case DisplayProtocol::DeleteGlobalBuffer::Opcode:
+      DispatchRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(
+          *this, &DisplayService::OnDeleteGlobalBuffer, message);
+      return {};
+
     case DisplayProtocol::GetGlobalBuffer::Opcode:
       DispatchRemoteMethod<DisplayProtocol::GetGlobalBuffer>(
           *this, &DisplayService::OnGetGlobalBuffer, message);
@@ -199,6 +271,36 @@
   }
 }
 
+pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnSetupGlobalBuffer(
+    pdx::Message& message, DvrGlobalBufferKey key, size_t size,
+    uint64_t usage) {
+  const int user_id = message.GetEffectiveUserId();
+  const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
+
+  if (!trusted) {
+    ALOGE(
+        "DisplayService::OnSetupGlobalBuffer: Permission denied for user_id=%d",
+        user_id);
+    return ErrorStatus(EPERM);
+  }
+  return SetupGlobalBuffer(key, size, usage);
+}
+
+pdx::Status<void> DisplayService::OnDeleteGlobalBuffer(pdx::Message& message,
+                                                       DvrGlobalBufferKey key) {
+  const int user_id = message.GetEffectiveUserId();
+  const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id);
+
+  if (!trusted) {
+    ALOGE(
+        "DisplayService::OnDeleteGlobalBuffer: Permission denied for "
+        "user_id=%d",
+        user_id);
+    return ErrorStatus(EPERM);
+  }
+  return DeleteGlobalBuffer(key);
+}
+
 pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetGlobalBuffer(
     pdx::Message& /* message */, DvrGlobalBufferKey key) {
   ALOGD_IF(TRACE, "DisplayService::OnGetGlobalBuffer: key=%d", key);
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index cb21e9f..6efe264 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -92,6 +92,11 @@
       pdx::Message& message, display::ConfigFileType config_type);
   pdx::Status<display::SurfaceInfo> OnCreateSurface(
       pdx::Message& message, const display::SurfaceAttributes& attributes);
+  pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer(
+      pdx::Message& message, DvrGlobalBufferKey key, size_t size,
+      uint64_t usage);
+  pdx::Status<void> OnDeleteGlobalBuffer(pdx::Message& message,
+                                         DvrGlobalBufferKey key);
 
   // Temporary query for current VR status. Will be removed later.
   pdx::Status<bool> IsVrAppRunning(pdx::Message& message);
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index d836fba..330b455 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -127,7 +127,8 @@
 }
 
 void DisplaySurface::ClearUpdate() {
-  ALOGD_IF(TRACE, "DisplaySurface::ClearUpdate: surface_id=%d", surface_id());
+  ALOGD_IF(TRACE > 1, "DisplaySurface::ClearUpdate: surface_id=%d",
+           surface_id());
   update_flags_ = display::SurfaceUpdateFlags::None;
 }
 
@@ -258,6 +259,13 @@
   }
 }
 
+std::vector<int32_t> DirectDisplaySurface::GetQueueIds() const {
+  std::vector<int32_t> queue_ids;
+  if (direct_queue_)
+    queue_ids.push_back(direct_queue_->id());
+  return queue_ids;
+}
+
 Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue(
     Message& /*message*/, const ProducerQueueConfig& config) {
   ATRACE_NAME("DirectDisplaySurface::OnCreateQueue");
@@ -326,7 +334,7 @@
     auto buffer_status = direct_queue_->Dequeue(0, &slot, &acquire_fence);
     if (!buffer_status) {
       ALOGD_IF(
-          TRACE && buffer_status.error() == ETIMEDOUT,
+          TRACE > 1 && buffer_status.error() == ETIMEDOUT,
           "DirectDisplaySurface::DequeueBuffersLocked: All buffers dequeued.");
       ALOGE_IF(buffer_status.error() != ETIMEDOUT,
                "DirectDisplaySurface::DequeueBuffersLocked: Failed to dequeue "
@@ -370,8 +378,8 @@
   }
   AcquiredBuffer buffer = std::move(acquired_buffers_.Front());
   acquired_buffers_.PopFront();
-  ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer: %p",
-           buffer.buffer().get());
+  ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer_id=%d",
+           buffer.buffer()->id());
   return buffer;
 }
 
@@ -399,8 +407,8 @@
       break;
   }
   ALOGD_IF(TRACE,
-           "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer: %p",
-           buffer.buffer().get());
+           "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer_id=%d",
+           buffer.buffer()->id());
   return buffer;
 }
 
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index 5380062..556183a 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -144,6 +144,7 @@
       : DisplaySurface(service, SurfaceType::Direct, surface_id, process_id,
                        user_id, attributes),
         acquired_buffers_(kMaxPostedBuffers) {}
+  std::vector<int32_t> GetQueueIds() const override;
   bool IsBufferAvailable();
   bool IsBufferPosted();
   AcquiredBuffer AcquireCurrentBuffer();
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
index 06b69bb..962c745 100644
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
+++ b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
@@ -101,12 +101,12 @@
     if (num_events < 0 && errno != EINTR)
       break;
 
-    ALOGD_IF(TRACE, "EpollEventDispatcher::EventThread: num_events=%d",
+    ALOGD_IF(TRACE > 1, "EpollEventDispatcher::EventThread: num_events=%d",
              num_events);
 
     for (int i = 0; i < num_events; i++) {
       ALOGD_IF(
-          TRACE,
+          TRACE > 1,
           "EpollEventDispatcher::EventThread: event %d: handler=%p events=0x%x",
           i, events[i].data.ptr, events[i].events);
 
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index c18ae82..d937c88 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -19,6 +19,8 @@
 #include <chrono>
 #include <functional>
 #include <map>
+#include <sstream>
+#include <string>
 #include <tuple>
 
 #include <dvr/dvr_display_types.h>
@@ -347,7 +349,36 @@
   return HWC::Error::None;
 }
 
-std::string HardwareComposer::Dump() { return hwc2_hidl_->dumpDebugInfo(); }
+std::string HardwareComposer::Dump() {
+  std::unique_lock<std::mutex> lock(post_thread_mutex_);
+  std::ostringstream stream;
+
+  stream << "Display metrics:     " << display_metrics_.width << "x"
+         << display_metrics_.height << " " << (display_metrics_.dpi.x / 1000.0)
+         << "x" << (display_metrics_.dpi.y / 1000.0) << " dpi @ "
+         << (1000000000.0 / display_metrics_.vsync_period_ns) << " Hz"
+         << std::endl;
+
+  stream << "Post thread resumed: " << post_thread_resumed_ << std::endl;
+  stream << "Active layers:       " << active_layer_count_ << std::endl;
+  stream << std::endl;
+
+  for (size_t i = 0; i < active_layer_count_; i++) {
+    stream << "Layer " << i << ":";
+    stream << " type=" << layers_[i].GetCompositionType().to_string();
+    stream << " surface_id=" << layers_[i].GetSurfaceId();
+    stream << " buffer_id=" << layers_[i].GetBufferId();
+    stream << std::endl;
+  }
+  stream << std::endl;
+
+  if (post_thread_resumed_) {
+    stream << "Hardware Composer Debug Info:" << std::endl;
+    stream << hwc2_hidl_->dumpDebugInfo();
+  }
+
+  return stream.str();
+}
 
 void HardwareComposer::PostLayers() {
   ATRACE_NAME("HardwareComposer::PostLayers");
@@ -398,10 +429,12 @@
     ATRACE_INT("frame_skip_count", 0);
   }
 
-#if TRACE
-  for (size_t i = 0; i < active_layer_count_; i++)
-    ALOGI("HardwareComposer::PostLayers: layer=%zu composition=%s", i,
+#if TRACE > 1
+  for (size_t i = 0; i < active_layer_count_; i++) {
+    ALOGI("HardwareComposer::PostLayers: layer=%zu buffer_id=%d composition=%s",
+          i, layers_[i].GetBufferId(),
           layers_[i].GetCompositionType().to_string().c_str());
+  }
 #endif
 
   error = Present(HWC_DISPLAY_PRIMARY);
@@ -440,19 +473,11 @@
     pending_surfaces_ = std::move(surfaces);
   }
 
-  // Set idle state based on whether there are any surfaces to handle.
-  UpdatePostThreadState(PostThreadState::Idle, display_idle);
-
-  // XXX: TEMPORARY
-  // Request control of the display based on whether there are any surfaces to
-  // handle. This callback sets the post thread active state once the transition
-  // is complete in SurfaceFlinger.
-  // TODO(eieio): Unify the control signal used to move SurfaceFlinger into VR
-  // mode. Currently this is hooked up to persistent VR mode, but perhaps this
-  // makes more sense to control it from VrCore, which could in turn base its
-  // decision on persistent VR mode.
   if (request_display_callback_)
     request_display_callback_(!display_idle);
+
+  // Set idle state based on whether there are any surfaces to handle.
+  UpdatePostThreadState(PostThreadState::Idle, display_idle);
 }
 
 int HardwareComposer::OnNewGlobalBuffer(DvrGlobalBufferKey key,
@@ -492,8 +517,9 @@
   int result = ion_buffer.Lock(ion_buffer.usage(), 0, 0, ion_buffer.width(),
                                ion_buffer.height(), &buffer_base);
   if (result != 0) {
-    ALOGE("HardwareComposer::MapConfigBuffer: Failed to map vrflinger config "
-          "buffer.");
+    ALOGE(
+        "HardwareComposer::MapConfigBuffer: Failed to map vrflinger config "
+        "buffer.");
     return -EPERM;
   }
 
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 98e8905..a0c50e1 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -127,11 +127,20 @@
     int surface_id = -1;
     pdx::rpc::IfAnyOf<SourceSurface>::Call(
         &source_, [&surface_id](const SourceSurface& surface_source) {
-          surface_id = surface_source.surface->surface_id();
+          surface_id = surface_source.GetSurfaceId();
         });
     return surface_id;
   }
 
+  int GetBufferId() const {
+    int buffer_id = -1;
+    pdx::rpc::IfAnyOf<SourceSurface>::Call(
+        &source_, [&buffer_id](const SourceSurface& surface_source) {
+          buffer_id = surface_source.GetBufferId();
+        });
+    return buffer_id;
+  }
+
  private:
   void CommonLayerSetup();
 
@@ -192,7 +201,15 @@
     }
 
     // Returns the surface id of the surface.
-    int GetSurfaceId() { return surface->surface_id(); }
+    int GetSurfaceId() const { return surface->surface_id(); }
+
+    // Returns the buffer id for the current buffer.
+    int GetBufferId() const {
+      if (acquired_buffer.IsAvailable())
+        return acquired_buffer.buffer()->id();
+      else
+        return -1;
+    }
   };
 
   // State when the layer is connected to a buffer. Provides the same interface
@@ -213,6 +230,7 @@
     IonBuffer* GetBuffer() { return buffer.get(); }
 
     int GetSurfaceId() const { return -1; }
+    int GetBufferId() const { return -1; }
   };
 
   // The underlying hardware composer layer is supplied buffers either from a
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 145852e..6c1995e 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -4,7 +4,7 @@
 #include <thread>
 #include <memory>
 
-#include <pdx/default_transport/service_dispatcher.h>
+#include <pdx/service_dispatcher.h>
 #include <vr/vr_manager/vr_manager.h>
 
 namespace android {
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index b2dc1d8..41526ee 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -18,8 +18,6 @@
 #include <sys/prctl.h>
 #include <sys/resource.h>
 
-#include <pdx/default_transport/service_dispatcher.h>
-
 #include <functional>
 
 #include "DisplayHardware/ComposerHal.h"
@@ -76,7 +74,7 @@
 
   request_display_callback_ = request_display_callback;
 
-  dispatcher_ = android::pdx::default_transport::ServiceDispatcher::Create();
+  dispatcher_ = android::pdx::ServiceDispatcher::Create();
   CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher.");
 
   display_service_ =
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
index 2a83933..3098b43 100644
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ b/libs/vr/libvrflinger/vsync_service.cpp
@@ -200,12 +200,12 @@
 }
 
 void VSyncChannel::Ack() {
-  ALOGD_IF(TRACE, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
+  ALOGD_IF(TRACE > 1, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
   service_.ModifyChannelEvents(cid_, POLLPRI, 0);
 }
 
 void VSyncChannel::Signal() {
-  ALOGD_IF(TRACE, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
+  ALOGD_IF(TRACE > 1, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
   service_.ModifyChannelEvents(cid_, 0, POLLPRI);
 }
 
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
index b21c7cf..4ddf1f3 100644
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ b/libs/vr/libvrsensor/pose_client.cpp
@@ -22,6 +22,11 @@
 
 namespace android {
 namespace dvr {
+namespace {
+
+typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing;
+
+}  // namespace
 
 // PoseClient is a remote interface to the pose service in sensord.
 class PoseClient : public pdx::ClientBase<PoseClient> {
@@ -36,16 +41,21 @@
   // Polls the pose service for the current state and stores it in *state.
   // Returns zero on success, a negative error code otherwise.
   int Poll(DvrPose* state) {
-    const auto vsync_buffer = GetVsyncBuffer();
-    if (vsync_buffer) {
-      if (state) {
-        // Fill the state
-        *state = vsync_buffer->current_pose;
-      }
-      return -EINVAL;
+    // Allocate the helper class to access the sensor pose buffer.
+    if (sensor_pose_buffer_ == nullptr) {
+      sensor_pose_buffer_ = std::make_unique<SensorPoseRing>(
+          DvrGlobalBuffers::kSensorPoseBuffer, CPUUsageMode::READ_RARELY);
     }
 
-    return -EAGAIN;
+    if (state) {
+      if (sensor_pose_buffer_->GetNewest(state)) {
+        return 0;
+      } else {
+        return -EAGAIN;
+      }
+    }
+
+    return -EINVAL;
   }
 
   int GetPose(uint32_t vsync_count, DvrPoseAsync* out_pose) {
@@ -235,6 +245,9 @@
   // The vsync pose buffer if already mapped.
   std::unique_ptr<CPUMappedBuffer> vsync_pose_buffer_;
 
+  // The direct sensor pose buffer.
+  std::unique_ptr<SensorPoseRing> sensor_pose_buffer_;
+
   const DvrVsyncPoseBuffer* mapped_vsync_pose_buffer_ = nullptr;
 
   struct ControllerClientState {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 97565aa..27009d0 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -147,7 +147,33 @@
 static const size_t keyCodeRotationMapSize =
         sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
 
+static int32_t rotateStemKey(int32_t value, int32_t orientation,
+        const int32_t map[][2], size_t mapSize) {
+    if (orientation == DISPLAY_ORIENTATION_180) {
+        for (size_t i = 0; i < mapSize; i++) {
+            if (value == map[i][0]) {
+                return map[i][1];
+            }
+        }
+    }
+    return value;
+}
+
+// The mapping can be defined using input device configuration properties keyboard.rotated.stem_X
+static int32_t stemKeyRotationMap[][2] = {
+        // key codes enumerated with the original (unrotated) key first
+        // no rotation,           180 degree rotation
+        { AKEYCODE_STEM_PRIMARY, AKEYCODE_STEM_PRIMARY },
+        { AKEYCODE_STEM_1,       AKEYCODE_STEM_1 },
+        { AKEYCODE_STEM_2,       AKEYCODE_STEM_2 },
+        { AKEYCODE_STEM_3,       AKEYCODE_STEM_3 },
+};
+static const size_t stemKeyRotationMapSize =
+        sizeof(stemKeyRotationMap) / sizeof(stemKeyRotationMap[0]);
+
 static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
+    keyCode = rotateStemKey(keyCode, orientation,
+            stemKeyRotationMap, stemKeyRotationMapSize);
     return rotateValueUsingRotationMap(keyCode, orientation,
             keyCodeRotationMap, keyCodeRotationMapSize);
 }
@@ -2260,18 +2286,36 @@
     }
 }
 
+static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const *property) {
+    int32_t mapped = 0;
+    if (config.tryGetProperty(String8(property), mapped) && mapped > 0) {
+        for (size_t i = 0; i < stemKeyRotationMapSize; i++) {
+            if (stemKeyRotationMap[i][0] == keyCode) {
+                stemKeyRotationMap[i][1] = mapped;
+                return;
+            }
+        }
+    }
+}
+
 void KeyboardInputMapper::configureParameters() {
     mParameters.orientationAware = false;
-    getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
+    const PropertyMap& config = getDevice()->getConfiguration();
+    config.tryGetProperty(String8("keyboard.orientationAware"),
             mParameters.orientationAware);
 
     mParameters.hasAssociatedDisplay = false;
     if (mParameters.orientationAware) {
         mParameters.hasAssociatedDisplay = true;
+
+        mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary");
+        mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1");
+        mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2");
+        mapStemKey(AKEYCODE_STEM_3, config, "keyboard.rotated.stem_3");
     }
 
     mParameters.handlesKeyRepeat = false;
-    getDevice()->getConfiguration().tryGetProperty(String8("keyboard.handlesKeyRepeat"),
+    config.tryGetProperty(String8("keyboard.handlesKeyRepeat"),
             mParameters.handlesKeyRepeat);
 }
 
@@ -2897,7 +2941,7 @@
 // --- RotaryEncoderInputMapper ---
 
 RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) :
-        InputMapper(device) {
+        InputMapper(device), mOrientation(DISPLAY_ORIENTATION_0) {
     mSource = AINPUT_SOURCE_ROTARY_ENCODER;
 }
 
@@ -2939,6 +2983,14 @@
     if (!changes) {
         mRotaryEncoderScrollAccumulator.configure(getDevice());
     }
+    if (!changes || (InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+        DisplayViewport v;
+        if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
+            mOrientation = v.orientation;
+        } else {
+            mOrientation = DISPLAY_ORIENTATION_0;
+        }
+    }
 }
 
 void RotaryEncoderInputMapper::reset(nsecs_t when) {
@@ -2976,6 +3028,10 @@
         policyFlags |= POLICY_FLAG_WAKE;
     }
 
+    if (mOrientation == DISPLAY_ORIENTATION_180) {
+        scroll = -scroll;
+    }
+
     // Send motion event.
     if (scrolled) {
         int32_t metaState = mContext->getGlobalMetaState();
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 157fa4f..803dcc9 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -1226,6 +1226,7 @@
 
     int32_t mSource;
     float mScalingFactor;
+    int32_t mOrientation;
 
     void sync(nsecs_t when);
 };
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index ab08cac..aa306d8 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -124,14 +124,15 @@
     forEachSensor([&result] (const Sensor& s) -> bool {
             result.appendFormat(
                     "%#010x) %-25s | %-15s | ver: %" PRId32 " | type: %20s(%" PRId32
-                        ") | perm: %s\n",
+                        ") | perm: %s | flags: 0x%08x\n",
                     s.getHandle(),
                     s.getName().string(),
                     s.getVendor().string(),
                     s.getVersion(),
                     s.getStringType().string(),
                     s.getType(),
-                    s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a");
+                    s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a",
+                    static_cast<int>(s.getFlags()));
 
             result.append("\t");
             const int reportingMode = s.getReportingMode();
@@ -173,9 +174,14 @@
                 result.appendFormat("non-wakeUp | ");
             }
 
+            if (s.isDataInjectionSupported()) {
+                result.appendFormat("data-injection, ");
+            }
+
             if (s.isDynamicSensor()) {
                 result.appendFormat("dynamic, ");
             }
+
             if (s.hasAdditionalInfo()) {
                 result.appendFormat("has-additional-info, ");
             }
@@ -190,7 +196,6 @@
                 if (s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_GRALLOC)) {
                     result.append("gralloc, ");
                 }
-                result.appendFormat("flag =0x%08x", static_cast<int>(s.getFlags()));
                 result.append("\n");
             }
             return true;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 209eea5..4e99756 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -933,8 +933,14 @@
     }
 
     uid_t uid = IPCThreadState::self()->getCallingUid();
-    sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName,
-            requestedMode == DATA_INJECTION, opPackageName));
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+
+    String8 connPackageName =
+            (packageName == "") ? String8::format("unknown_package_pid_%d", pid) : packageName;
+    String16 connOpPackageName =
+            (opPackageName == String16("")) ? String16(connPackageName) : opPackageName;
+    sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
+            requestedMode == DATA_INJECTION, connOpPackageName));
     if (requestedMode == DATA_INJECTION) {
         if (mActiveConnections.indexOf(result) < 0) {
             mActiveConnections.add(result);
diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp
index 8bbc4c5..02c13fa 100644
--- a/services/sensorservice/hidl/Android.bp
+++ b/services/sensorservice/hidl/Android.bp
@@ -14,6 +14,7 @@
         "libbase",
         "libhidlbase",
         "libhidltransport",
+        "libhwbinder",
         "libutils",
         "libsensor",
         "android.frameworks.sensorservice@1.0",
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index 991944e..f1f52d8 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -30,6 +30,9 @@
 #include "DirectReportChannel.h"
 #include "utils.h"
 
+#include <hwbinder/IPCThreadState.h>
+#include <utils/String8.h>
+
 namespace android {
 namespace frameworks {
 namespace sensorservice {
@@ -42,7 +45,10 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
-SensorManager::SensorManager() {
+static const char* POLL_THREAD_NAME = "hidl_ssvc_poll";
+
+SensorManager::SensorManager(JavaVM* vm)
+        : mJavaVm(vm) {
 }
 
 SensorManager::~SensorManager() {
@@ -130,7 +136,7 @@
     if (mLooper == nullptr) {
         std::condition_variable looperSet;
 
-        std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet] {
+        std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet, javaVm = mJavaVm] {
 
             struct sched_param p = {0};
             p.sched_priority = 10;
@@ -140,14 +146,35 @@
             }
 
             std::unique_lock<std::mutex> lock(mutex);
+            if (looper != nullptr) {
+                LOG(INFO) << "Another thread has already set the looper, exiting this one.";
+                return;
+            }
             looper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS /* opts */);
             lock.unlock();
 
+            // Attach the thread to JavaVM so that pollAll do not crash if the event
+            // is from Java.
+            JavaVMAttachArgs args{
+                .version = JNI_VERSION_1_2,
+                .name = POLL_THREAD_NAME,
+                .group = NULL
+            };
+            JNIEnv* env;
+            if (javaVm->AttachCurrentThread(&env, &args) != JNI_OK) {
+                LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM.";
+            }
+
             looperSet.notify_one();
             int pollResult = looper->pollAll(-1 /* timeout */);
             if (pollResult != ALOOPER_POLL_WAKE) {
                 LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult;
             }
+
+            if (javaVm->DetachCurrentThread() != JNI_OK) {
+                LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM.";
+            }
+
             LOG(INFO) << "Looper thread is terminated.";
         }}.detach();
         looperSet.wait(lock, [this]{ return this->mLooper != nullptr; });
@@ -172,7 +199,9 @@
     }
 
     sp<::android::Looper> looper = getLooper();
-    sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue();
+    String8 package(String8::format("hidl_client_pid_%d",
+                                    android::hardware::IPCThreadState::self()->getCallingPid()));
+    sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(package);
     if (internalQueue == nullptr) {
         LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr.";
         _hidl_cb(nullptr, Result::UNKNOWN_ERROR);
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index cc044bf..e66c8e5 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_SENSORMANAGER_H
 #define ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_SENSORMANAGER_H
 
+#include <jni.h>
+
 #include <mutex>
 
 #include <android/frameworks/sensorservice/1.0/ISensorManager.h>
@@ -39,7 +41,7 @@
 
 struct SensorManager final : public ISensorManager {
 
-    SensorManager();
+    SensorManager(JavaVM* vm);
     ~SensorManager();
 
     // Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
@@ -59,6 +61,8 @@
 
     std::mutex mLooperMutex;
     sp<::android::Looper> mLooper;
+
+    JavaVM* mJavaVm;
 };
 
 }  // namespace implementation
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index e9a2513..8ba6cb9 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -57,9 +57,19 @@
 }
 
 void Client::setParentLayer(const sp<Layer>& parentLayer) {
+    Mutex::Autolock _l(mLock);
     mParentLayer = parentLayer;
 }
 
+sp<Layer> Client::getParentLayer(bool* outParentDied) const {
+    Mutex::Autolock _l(mLock);
+    sp<Layer> parent = mParentLayer.promote();
+    if (outParentDied != nullptr) {
+        *outParentDied = (mParentLayer != nullptr && parent == nullptr);
+    }
+    return parent;
+}
+
 status_t Client::initCheck() const {
     return NO_ERROR;
 }
@@ -108,7 +118,7 @@
      // We grant an exception in the case that the Client has a "parent layer", as its
      // effects will be scoped to that layer.
      if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)
-             && (mParentLayer.promote() == nullptr)) {
+             && (getParentLayer() == nullptr)) {
          // we're called from a different process, do the real check
          if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger))
          {
@@ -135,11 +145,12 @@
             return NAME_NOT_FOUND;
         }
     }
-    if (parent == nullptr && mParentLayer != nullptr) {
-        parent = mParentLayer.promote();
+    if (parent == nullptr) {
+        bool parentDied;
+        parent = getParentLayer(&parentDied);
         // If we had a parent, but it died, we've lost all
         // our capabilities.
-        if (parent == nullptr) {
+        if (parentDied) {
             return NAME_NOT_FOUND;
         }
     }
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index b5f98b8..2aab28f 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -71,12 +71,13 @@
     virtual status_t onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
 
+    sp<Layer> getParentLayer(bool* outParentDied = nullptr) const;
+
     // constant
     sp<SurfaceFlinger> mFlinger;
 
     // protected by mLock
     DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayers;
-
     wp<Layer> mParentLayer;
 
     // thread-safe
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index bd9b8aa..ac8aa04 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -30,7 +30,7 @@
 #include <utils/Trace.h>
 #include <utils/Vector.h>
 
-#include <ui/Fence.h>
+#include <ui/FenceTime.h>
 
 #include "DispSync.h"
 #include "SurfaceFlinger.h"
@@ -419,25 +419,13 @@
     resetErrorLocked();
 }
 
-bool DispSync::addPresentFence(const sp<Fence>& fence) {
+bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
     Mutex::Autolock lock(mMutex);
 
-    mPresentFences[mPresentSampleOffset] = fence;
-    mPresentTimes[mPresentSampleOffset] = 0;
+    mPresentFences[mPresentSampleOffset] = fenceTime;
     mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES;
     mNumResyncSamplesSincePresent = 0;
 
-    for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
-        const sp<Fence>& f(mPresentFences[i]);
-        if (f != NULL) {
-            nsecs_t t = f->getSignalTime();
-            if (t < INT64_MAX) {
-                mPresentFences[i].clear();
-                mPresentTimes[i] = t + mPresentTimeOffset;
-            }
-        }
-    }
-
     updateErrorLocked();
 
     return !mModelUpdated || mError > kErrorThreshold;
@@ -602,21 +590,39 @@
     nsecs_t sqErrSum = 0;
 
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
-        nsecs_t sample = mPresentTimes[i] - mReferenceTime;
-        if (sample > mPhase) {
-            nsecs_t sampleErr = (sample - mPhase) % period;
-            if (sampleErr > period / 2) {
-                sampleErr -= period;
-            }
-            sqErrSum += sampleErr * sampleErr;
-            numErrSamples++;
+        // Only check for the cached value of signal time to avoid unecessary
+        // syscalls. It is the responsibility of the DispSync owner to
+        // call getSignalTime() periodically so the cache is updated when the
+        // fence signals.
+        nsecs_t time = mPresentFences[i]->getCachedSignalTime();
+        if (time == Fence::SIGNAL_TIME_PENDING ||
+                time == Fence::SIGNAL_TIME_INVALID) {
+            continue;
         }
+
+        nsecs_t sample = time - mReferenceTime;
+        if (sample <= mPhase) {
+            continue;
+        }
+
+        nsecs_t sampleErr = (sample - mPhase) % period;
+        if (sampleErr > period / 2) {
+            sampleErr -= period;
+        }
+        sqErrSum += sampleErr * sampleErr;
+        numErrSamples++;
     }
 
     if (numErrSamples > 0) {
         mError = sqErrSum / numErrSamples;
+        mZeroErrSamplesCount = 0;
     } else {
         mError = 0;
+        // Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam.
+        mZeroErrSamplesCount++;
+        ALOGE_IF(
+                (mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
+                "No present times for model error.");
     }
 
     if (kTraceDetailedInfo) {
@@ -627,9 +633,9 @@
 void DispSync::resetErrorLocked() {
     mPresentSampleOffset = 0;
     mError = 0;
+    mZeroErrSamplesCount = 0;
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
-        mPresentFences[i].clear();
-        mPresentTimes[i] = 0;
+        mPresentFences[i] = FenceTime::NO_FENCE;
     }
 }
 
@@ -668,19 +674,19 @@
         previous = sampleTime;
     }
 
-    result.appendFormat("mPresentFences / mPresentTimes [%d]:\n",
+    result.appendFormat("mPresentFences [%d]:\n",
             NUM_PRESENT_SAMPLES);
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    previous = 0;
+    previous = Fence::SIGNAL_TIME_INVALID;
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
         size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES;
-        bool signaled = mPresentFences[idx] == NULL;
-        nsecs_t presentTime = mPresentTimes[idx];
-        if (!signaled) {
+        nsecs_t presentTime = mPresentFences[idx]->getSignalTime();
+        if (presentTime == Fence::SIGNAL_TIME_PENDING) {
             result.appendFormat("  [unsignaled fence]\n");
-        } else if (presentTime == 0) {
-            result.appendFormat("  0\n");
-        } else if (previous == 0) {
+        } else if(presentTime == Fence::SIGNAL_TIME_INVALID) {
+            result.appendFormat("  [invalid fence]\n");
+        } else if (previous == Fence::SIGNAL_TIME_PENDING ||
+                previous == Fence::SIGNAL_TIME_INVALID) {
             result.appendFormat("  %" PRId64 "  (%.3f ms ago)\n", presentTime,
                     (now - presentTime) / 1000000.0);
         } else {
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 82ae795..c9f3b04 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -23,10 +23,14 @@
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 
+#include <ui/FenceTime.h>
+
+#include <memory>
+
 namespace android {
 
 class String8;
-class Fence;
+class FenceTime;
 class DispSyncThread;
 
 // DispSync maintains a model of the periodic hardware-based vsync events of a
@@ -67,7 +71,7 @@
     //
     // This method should be called with the retire fence from each HWComposer
     // set call that affects the display.
-    bool addPresentFence(const sp<Fence>& fence);
+    bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
 
     // The beginResync, addResyncSample, and endResync methods are used to re-
     // synchronize the DispSync's model to the hardware vsync events.  The re-
@@ -129,6 +133,7 @@
     enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 };
     enum { NUM_PRESENT_SAMPLES = 8 };
     enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
+    enum { ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT = 64 };
 
     const char* const mName;
 
@@ -146,9 +151,14 @@
 
     // mError is the computed model error.  It is based on the difference
     // between the estimated vsync event times and those observed in the
-    // mPresentTimes array.
+    // mPresentFences array.
     nsecs_t mError;
 
+    // mZeroErrSamplesCount keeps track of how many times in a row there were
+    // zero timestamps available in the mPresentFences array.
+    // Used to sanity check that we are able to calculate the model error.
+    size_t mZeroErrSamplesCount;
+
     // Whether we have updated the vsync event model since the last resync.
     bool mModelUpdated;
 
@@ -162,8 +172,8 @@
 
     // These member variables store information about the present fences used
     // to validate the currently computed model.
-    sp<Fence> mPresentFences[NUM_PRESENT_SAMPLES];
-    nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES];
+    std::shared_ptr<FenceTime>
+            mPresentFences[NUM_PRESENT_SAMPLES] {FenceTime::NO_FENCE};
     size_t mPresentSampleOffset;
 
     int mRefreshSkipCount;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 15a43df..b7376d0 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -35,6 +35,7 @@
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
+#include <map>
 
 namespace android {
     class Fence;
@@ -283,7 +284,9 @@
     bool mIsConnected;
     DisplayType mType;
     std::unordered_map<hwc2_layer_t, std::weak_ptr<Layer>> mLayers;
-    std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
+    // The ordering in this map matters, for getConfigs(), when it is
+    // converted to a vector
+    std::map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
 };
 
 // Convenience C++ class to access hwc2_device_t Layer functions directly.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1b9a230..a7d53e9 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -405,7 +405,7 @@
         win.intersect(s.finalCrop, &win);
     }
 
-    const sp<Layer>& p = getParent();
+    const sp<Layer>& p = mDrawingParent.promote();
     // Now we need to calculate the parent bounds, so we can clip ourselves to those.
     // When calculating the parent bounds for purposes of clipping,
     // we don't need to constrain the parent to its transparent region.
@@ -442,7 +442,7 @@
     }
 
     Rect bounds = win;
-    const auto& p = getParent();
+    const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
         // Look in computeScreenBounds recursive call for explanation of
         // why we pass false here.
@@ -500,7 +500,7 @@
 
     // Screen space to make reduction to parent crop clearer.
     Rect activeCrop = computeInitialCrop(hw);
-    const auto& p = getParent();
+    const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
         auto parentCrop = p->computeInitialCrop(hw);
         activeCrop.intersect(parentCrop, &activeCrop);
@@ -712,7 +712,7 @@
 
     int type = s.type;
     int appId = s.appId;
-    sp<Layer> parent = mParent.promote();
+    sp<Layer> parent = mDrawingParent.promote();
     if (parent.get()) {
         auto& parentState = parent->getDrawingState();
         type = parentState.type;
@@ -1108,8 +1108,9 @@
              * of a camera where the buffer remains in native orientation,
              * we want the pixels to always be upright.
              */
-            if (getParent() != nullptr) {
-                const auto parentTransform = getParent()->getTransform();
+            sp<Layer> p = mDrawingParent.promote();
+            if (p != nullptr) {
+                const auto parentTransform = p->getTransform();
                 tr = tr * inverseOrientation(parentTransform.getOrientation());
             }
 
@@ -1308,7 +1309,8 @@
         // able to be latched. To avoid this, grab this buffer anyway.
         return true;
     }
-    return mQueueItems[0].mFence->getSignalTime() != INT64_MAX;
+    return mQueueItems[0].mFenceTime->getSignalTime() !=
+            Fence::SIGNAL_TIME_PENDING;
 #else
     return true;
 #endif
@@ -1933,7 +1935,7 @@
 }
 
 uint32_t Layer::getLayerStack() const {
-    auto p = getParent();
+    auto p = mDrawingParent.promote();
     if (p == nullptr) {
         return getDrawingState().layerStack;
     }
@@ -2011,9 +2013,6 @@
 bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
         const std::shared_ptr<FenceTime>& presentFence,
         const CompositorTiming& compositorTiming) {
-    mAcquireTimeline.updateSignalTimes();
-    mReleaseTimeline.updateSignalTimes();
-
     // mFrameLatencyNeeded is true when a new frame was latched for the
     // composition.
     if (!mFrameLatencyNeeded)
@@ -2064,6 +2063,7 @@
 
     auto releaseFenceTime = std::make_shared<FenceTime>(
             mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+    mReleaseTimeline.updateSignalTimes();
     mReleaseTimeline.push(releaseFenceTime);
 
     Mutex::Autolock lock(mFrameEventHistoryMutex);
@@ -2076,7 +2076,7 @@
 
 bool Layer::isHiddenByPolicy() const {
     const Layer::State& s(mDrawingState);
-    const auto& parent = getParent();
+    const auto& parent = mDrawingParent.promote();
     if (parent != nullptr && parent->isHiddenByPolicy()) {
         return true;
     }
@@ -2254,6 +2254,7 @@
 #ifndef USE_HWC2
         auto releaseFenceTime = std::make_shared<FenceTime>(
                 mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+        mReleaseTimeline.updateSignalTimes();
         mReleaseTimeline.push(releaseFenceTime);
         if (mPreviousFrameNumber != 0) {
             mFrameEventHistory.addRelease(mPreviousFrameNumber,
@@ -2509,6 +2510,12 @@
         FrameEventHistoryDelta *outDelta) {
     Mutex::Autolock lock(mFrameEventHistoryMutex);
     if (newTimestamps) {
+        // If there are any unsignaled fences in the aquire timeline at this
+        // point, the previously queued frame hasn't been latched yet. Go ahead
+        // and try to get the signal time here so the syscall is taken out of
+        // the main thread's critical path.
+        mAcquireTimeline.updateSignalTimes();
+        // Push the new fence after updating since it's likely still pending.
         mAcquireTimeline.push(newTimestamps->acquireFence);
         mFrameEventHistory.addQueue(*newTimestamps);
     }
@@ -2567,25 +2574,7 @@
     }
 
     for (const sp<Layer>& child : mCurrentChildren) {
-        // We don't call addChild as we need to delay updating the child's parent pointer until
-        // a transaction occurs. Remember a refresh could occur in between now and the next
-        // transaction, in which case the Layer's parent pointer would be updated, but changes
-        // made to the parent in the same transaction would not have applied.
-        // This means that the following kind of scenario wont work:
-        //
-        // 1. Existing and visible child and parent surface exist
-        // 2. Create new surface hidden
-        // 3. Open transaction
-        // 4. Show the new surface, and reparent the old surface's children to it.
-        // 5. Close transaction.
-        //
-        // If we were to update the parent pointer immediately, then the child surface
-        // could disappear for one frame as it pointed at the new parent which
-        // hasn't yet become visible as the transaction hasn't yet occurred.
-        //
-        // Instead we defer the reparenting to commitChildList which happens as part
-        // of the global transaction.
-        newParent->mCurrentChildren.add(child);
+        newParent->addChild(child);
 
         sp<Client> client(child->mClientRef.promote());
         if (client != nullptr) {
@@ -2613,7 +2602,7 @@
 }
 
 void Layer::setParent(const sp<Layer>& layer) {
-    mParent = layer;
+    mCurrentParent = layer;
 }
 
 void Layer::clearSyncPoints() {
@@ -2703,7 +2692,7 @@
 
 Transform Layer::getTransform() const {
     Transform t;
-    const auto& p = getParent();
+    const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
         t = p->getTransform();
 
@@ -2736,14 +2725,14 @@
 
 #ifdef USE_HWC2
 float Layer::getAlpha() const {
-    const auto& p = getParent();
+    const auto& p = mDrawingParent.promote();
 
     float parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0;
     return parentAlpha * getDrawingState().alpha;
 }
 #else
 uint8_t Layer::getAlpha() const {
-    const auto& p = getParent();
+    const auto& p = mDrawingParent.promote();
 
     float parentAlpha = (p != nullptr) ? (p->getAlpha() / 255.0f) : 1.0;
     float drawingAlpha = getDrawingState().alpha / 255.0f;
@@ -2755,11 +2744,10 @@
 void Layer::commitChildList() {
     for (size_t i = 0; i < mCurrentChildren.size(); i++) {
         const auto& child = mCurrentChildren[i];
-        child->setParent(this);
-
         child->commitChildList();
     }
     mDrawingChildren = mCurrentChildren;
+    mDrawingParent = mCurrentParent;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6955d73..6ed372c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -523,7 +523,7 @@
     // Returns index if removed, or negative value otherwise
     // for symmetry with Vector::remove
     ssize_t removeChild(const sp<Layer>& layer);
-    sp<Layer> getParent() const { return mParent.promote(); }
+    sp<Layer> getParent() const { return mCurrentParent.promote(); }
     bool hasParent() const { return getParent() != nullptr; }
 
     Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
@@ -801,7 +801,8 @@
     // Child list used for rendering.
     LayerVector mDrawingChildren;
 
-    wp<Layer> mParent;
+    wp<Layer> mCurrentParent;
+    wp<Layer> mDrawingParent;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 85a33c8..14f50bb 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -30,6 +30,8 @@
 
 #include "Barrier.h"
 
+#include <functional>
+
 namespace android {
 
 class IDisplayEventConnection;
@@ -58,6 +60,21 @@
     mutable Barrier barrier;
 };
 
+class LambdaMessage : public MessageBase {
+public:
+    explicit LambdaMessage(std::function<void()> handler)
+          : MessageBase(), mHandler(std::move(handler)) {}
+
+    bool handler() override {
+        mHandler();
+        // This return value is no longer checked, so it's always safe to return true
+        return true;
+    }
+
+private:
+    const std::function<void()> mHandler;
+};
+
 // ---------------------------------------------------------------------------
 
 class MessageQueue {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 78579a5..c19ffe4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -225,6 +225,9 @@
     property_get("ro.sf.disable_triple_buffer", value, "1");
     mLayerTripleBufferingDisabled = atoi(value);
     ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
+
+    property_get("persist.sys.sf.color_saturation", value, "1.0");
+    mSaturation = atof(value);
 }
 
 void SurfaceFlinger::onFirstRef()
@@ -1026,8 +1029,13 @@
 
 // ----------------------------------------------------------------------------
 
-sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
-    return mEventThread->createEventConnection();
+sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
+        ISurfaceComposer::VsyncSource vsyncSource) {
+    if (vsyncSource == eVsyncSourceSurfaceFlinger) {
+        return mSFEventThread->createEventConnection();
+    } else {
+        return mEventThread->createEventConnection();
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -1315,11 +1323,21 @@
     // parts of this class rely on the primary display always being available.
     createDefaultDisplayDevice();
 
-    // Reset the timing values to account for the period of the swapped in HWC
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
-    const nsecs_t period = activeConfig->getVsyncPeriod();
-    mAnimFrameTracker.setDisplayRefreshPeriod(period);
-    setCompositorTimingSnapped(0, period, 0);
+    // Re-enable default display.
+    sp<LambdaMessage> requestMessage = new LambdaMessage([&]() {
+        sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
+        setPowerModeInternal(hw, HWC_POWER_MODE_NORMAL);
+
+        // Reset the timing values to account for the period of the swapped in HWC
+        const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+        const nsecs_t period = activeConfig->getVsyncPeriod();
+        mAnimFrameTracker.setDisplayRefreshPeriod(period);
+
+        // Use phase of 0 since phase is not known.
+        // Use latency of 0, which will snap to the ideal latency.
+        setCompositorTimingSnapped(0, period, 0);
+    });
+    postMessageAsync(requestMessage);
 
     android_atomic_or(1, &mRepaintEverything);
     setTransactionFlags(eDisplayTransactionNeeded);
@@ -1535,6 +1553,7 @@
     // |mStateLock| not needed as we are on the main thread
     const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
 
+    mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
     if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
         glCompositionDoneFenceTime =
@@ -1543,12 +1562,11 @@
     } else {
         glCompositionDoneFenceTime = FenceTime::NO_FENCE;
     }
-    mGlCompositionDoneTimeline.updateSignalTimes();
 
+    mDisplayTimeline.updateSignalTimes();
     sp<Fence> presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
     auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
     mDisplayTimeline.push(presentFenceTime);
-    mDisplayTimeline.updateSignalTimes();
 
     nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
     nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
@@ -1573,8 +1591,8 @@
         }
     });
 
-    if (presentFence->isValid()) {
-        if (mPrimaryDispSync.addPresentFence(presentFence)) {
+    if (presentFenceTime->isValid()) {
+        if (mPrimaryDispSync.addPresentFence(presentFenceTime)) {
             enableHardwareVsync();
         } else {
             disableHardwareVsync(false);
@@ -2702,14 +2720,16 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) {
     Mutex::Autolock _l(mStateLock);
 
     const auto& p = layer->getParent();
-    const ssize_t index = (p != nullptr) ? p->removeChild(layer) :
-        mCurrentState.layersSortedByZ.remove(layer);
-
+    ssize_t index;
     if (p != nullptr) {
+        if (topLevelOnly) {
+            return NO_ERROR;
+        }
+
         sp<Layer> ancestor = p;
         while (ancestor->getParent() != nullptr) {
             ancestor = ancestor->getParent();
@@ -2718,6 +2738,10 @@
             ALOGE("removeLayer called with a layer whose parent has been removed");
             return NAME_NOT_FOUND;
         }
+
+        index = p->removeChild(layer);
+    } else {
+        index = mCurrentState.layersSortedByZ.remove(layer);
     }
 
     // As a matter of normal operation, the LayerCleaner will produce a second
@@ -3148,11 +3172,9 @@
     if (l == nullptr) {
         // The layer has already been removed, carry on
         return NO_ERROR;
-    } if (l->getParent() != nullptr) {
-        // If we have a parent, then we can continue to live as long as it does.
-        return NO_ERROR;
     }
-    return removeLayer(l);
+    // If we have a parent, then we can continue to live as long as it does.
+    return removeLayer(l, true);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 68a088a..2360a61 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -277,7 +277,8 @@
         const sp<IGraphicBufferProducer>& bufferProducer) const;
     virtual status_t getSupportedFrameTimestamps(
             std::vector<FrameEvent>* outSupported) const;
-    virtual sp<IDisplayEventConnection> createDisplayEventConnection();
+    virtual sp<IDisplayEventConnection> createDisplayEventConnection(
+            ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
     virtual status_t captureScreen(const sp<IBinder>& display,
             const sp<IGraphicBufferProducer>& producer,
             Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
@@ -395,7 +396,7 @@
     status_t onLayerDestroyed(const wp<Layer>& layer);
 
     // remove a layer from SurfaceFlinger immediately
-    status_t removeLayer(const sp<Layer>& layer);
+    status_t removeLayer(const sp<Layer>& layer, bool topLevelOnly = false);
 
     // add a layer to SurfaceFlinger
     status_t addClientLayer(const sp<Client>& client,
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 0b3a0d0..2972485 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -933,8 +933,13 @@
 
 // ----------------------------------------------------------------------------
 
-sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
-    return mEventThread->createEventConnection();
+sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
+        ISurfaceComposer::VsyncSource vsyncSource) {
+    if (vsyncSource == eVsyncSourceSurfaceFlinger) {
+        return mSFEventThread->createEventConnection();
+    } else {
+        return mEventThread->createEventConnection();
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -1252,6 +1257,7 @@
     const HWComposer& hwc = getHwComposer();
     const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
 
+    mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
     if (getHwComposer().hasGlesComposition(hw->getHwcDisplayId())) {
         glCompositionDoneFenceTime =
@@ -1260,12 +1266,11 @@
     } else {
         glCompositionDoneFenceTime = FenceTime::NO_FENCE;
     }
-    mGlCompositionDoneTimeline.updateSignalTimes();
 
+    mDisplayTimeline.updateSignalTimes();
     sp<Fence> retireFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY);
     auto retireFenceTime = std::make_shared<FenceTime>(retireFence);
     mDisplayTimeline.push(retireFenceTime);
-    mDisplayTimeline.updateSignalTimes();
 
     nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
     nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
@@ -1293,7 +1298,7 @@
     });
 
     if (retireFence->isValid()) {
-        if (mPrimaryDispSync.addPresentFence(retireFence)) {
+        if (mPrimaryDispSync.addPresentFence(retireFenceTime)) {
             enableHardwareVsync();
         } else {
             disableHardwareVsync(false);
@@ -2322,8 +2327,13 @@
         if (parent == nullptr) {
             mCurrentState.layersSortedByZ.add(lbc);
         } else {
+            if (mCurrentState.layersSortedByZ.indexOf(parent) < 0) {
+                ALOGE("addClientLayer called with a removed parent");
+                return NAME_NOT_FOUND;
+            }
             parent->addChild(lbc);
         }
+
         mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
         mLayersAdded = true;
         mNumLayers++;
@@ -2335,12 +2345,29 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) {
     Mutex::Autolock _l(mStateLock);
 
     const auto& p = layer->getParent();
-    const ssize_t index = (p != nullptr) ? p->removeChild(layer) :
-             mCurrentState.layersSortedByZ.remove(layer);
+    ssize_t index;
+    if (p != nullptr) {
+        if (topLevelOnly) {
+            return NO_ERROR;
+        }
+
+        sp<Layer> ancestor = p;
+        while (ancestor->getParent() != nullptr) {
+            ancestor = ancestor->getParent();
+        }
+        if (mCurrentState.layersSortedByZ.indexOf(ancestor) < 0) {
+            ALOGE("removeLayer called with a layer whose parent has been removed");
+            return NAME_NOT_FOUND;
+        }
+
+        index = p->removeChild(layer);
+    } else {
+        index = mCurrentState.layersSortedByZ.remove(layer);
+    }
 
     // As a matter of normal operation, the LayerCleaner will produce a second
     // attempt to remove the surface. The Layer will be kept alive in mDrawingState
@@ -2358,7 +2385,7 @@
 
     mLayersPendingRemoval.add(layer);
     mLayersRemoved = true;
-    mNumLayers--;
+    mNumLayers -= 1 + layer->getChildrenCount();
     setTransactionFlags(eTransactionNeeded);
     return NO_ERROR;
 }
@@ -2765,11 +2792,9 @@
     if (l == nullptr) {
         // The layer has already been removed, carry on
         return NO_ERROR;
-    } if (l->getParent() != nullptr) {
-        // If we have a parent, then we can continue to live as long as it does.
-        return NO_ERROR;
     }
-    return removeLayer(l);
+    // If we have a parent, then we can continue to live as long as it does.
+    return removeLayer(l, true);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/vr/bufferhubd/bufferhubd.cpp b/services/vr/bufferhubd/bufferhubd.cpp
index d4fc540..1613821 100644
--- a/services/vr/bufferhubd/bufferhubd.cpp
+++ b/services/vr/bufferhubd/bufferhubd.cpp
@@ -4,7 +4,7 @@
 #include <log/log.h>
 
 #include <dvr/performance_client_api.h>
-#include <pdx/default_transport/service_dispatcher.h>
+#include <pdx/service_dispatcher.h>
 
 #include "buffer_hub.h"
 
@@ -16,7 +16,7 @@
   // We need to be able to create endpoints with full perms.
   umask(0000);
 
-  dispatcher = android::pdx::default_transport::ServiceDispatcher::Create();
+  dispatcher = android::pdx::ServiceDispatcher::Create();
   CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher\n");
 
   service = android::dvr::BufferHubService::Create();
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 565e5d3..9bbb7f3 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -336,7 +336,19 @@
       *outValue = display_ptr->height();
       break;
     case IComposerClient::Attribute::VSYNC_PERIOD:
-      *outValue = 1000 * 1000 * 1000 / 30;  // 30fps
+      {
+        int error = 0;
+        auto display_client = display::DisplayClient::Create(&error);
+        if (!display_client) {
+          ALOGE("Could not connect to display service : %s(%d)",
+                strerror(error), error);
+          // Return a default value of 30 fps
+          *outValue = 1000 * 1000 * 1000 / 30;
+        } else {
+          auto metrics = display_client->GetDisplayMetrics();
+          *outValue = metrics.get().vsync_period_ns;
+        }
+      }
       break;
     case IComposerClient::Attribute::DPI_X:
     case IComposerClient::Attribute::DPI_Y:
diff --git a/services/vr/performanced/main.cpp b/services/vr/performanced/main.cpp
index ca66c71..d7dc8f6 100644
--- a/services/vr/performanced/main.cpp
+++ b/services/vr/performanced/main.cpp
@@ -9,7 +9,7 @@
 #include <sys/resource.h>
 #include <utils/threads.h>
 
-#include <pdx/default_transport/service_dispatcher.h>
+#include <pdx/service_dispatcher.h>
 #include <private/android_filesystem_config.h>
 
 #include "performance_service.h"
@@ -58,7 +58,7 @@
   CHECK_ERROR(ret < 0, error, "Could not set capabilities: %s",
               strerror(errno));
 
-  dispatcher = android::pdx::default_transport::ServiceDispatcher::Create();
+  dispatcher = android::pdx::ServiceDispatcher::Create();
   CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher.");
 
   service = android::dvr::PerformanceService::Create();
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index b9aa8fe..6b11ce3 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -33,9 +33,6 @@
 test_static_libs = [
     "libcutils",
     "libvirtualtouchpad",
-]
-
-test_shared_libs = [
     "libbase",
     "liblog",
     "libutils",
@@ -46,7 +43,6 @@
 cc_test {
     srcs: test_src_files,
     static_libs: test_static_libs,
-    shared_libs: test_shared_libs,
     header_libs: header_libraries,
     cppflags = [
         "-std=c++11",
diff --git a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
index eb152ed..3ab77a7 100644
--- a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
@@ -40,6 +40,11 @@
   return FromC(client)->ButtonState(touchpad, buttons);
 }
 
+int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x,
+                             float y) {
+  return FromC(client)->Scroll(touchpad, x, y);
+}
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/services/vr/virtual_touchpad/EvdevInjector.cpp b/services/vr/virtual_touchpad/EvdevInjector.cpp
index a4ccdd0..7fad379 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.cpp
+++ b/services/vr/virtual_touchpad/EvdevInjector.cpp
@@ -168,6 +168,25 @@
   return ConfigureAbs(ABS_MT_SLOT, 0, slots, 0, 0);
 }
 
+int EvdevInjector::ConfigureRel(uint16_t rel_type) {
+  ALOGV("ConfigureRel 0x%" PRIX16 "", rel_type);
+  if (rel_type < 0 || rel_type >= REL_CNT) {
+    ALOGE("EV_REL type 0x%" PRIX16 " out of range [0,0x%X)", rel_type, REL_CNT);
+    return Error(ERROR_REL_RANGE);
+  }
+  if (const int status = RequireState(State::CONFIGURING)) {
+    return status;
+  }
+  if (const int status = EnableEventType(EV_REL)) {
+    return status;
+  }
+  if (const int status = uinput_->IoctlSetInt(UI_SET_RELBIT, rel_type)) {
+    ALOGE("failed to enable EV_REL 0x%" PRIX16 "", rel_type);
+    return Error(status);
+  }
+  return 0;
+}
+
 int EvdevInjector::ConfigureEnd() {
   ALOGV("ConfigureEnd:");
   ALOGV("  name=\"%s\"", uidev_.name);
@@ -236,6 +255,10 @@
   return Send(EV_ABS, code, value);
 }
 
+int EvdevInjector::SendRel(uint16_t code, int32_t value) {
+  return Send(EV_REL, code, value);
+}
+
 int EvdevInjector::SendMultiTouchSlot(int32_t slot) {
   if (latest_slot_ != slot) {
     if (const int status = SendAbs(ABS_MT_SLOT, slot)) {
diff --git a/services/vr/virtual_touchpad/EvdevInjector.h b/services/vr/virtual_touchpad/EvdevInjector.h
index c69dbef..e87c959 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.h
+++ b/services/vr/virtual_touchpad/EvdevInjector.h
@@ -30,6 +30,7 @@
     ERROR_KEY_RANGE = -3,       // |KEY_*|/|BTN_*| code out of range.
     ERROR_ABS_RANGE = -4,       // |ABS_*| code out of range.
     ERROR_SEQUENCING = -5,      // Configure/Send out of order.
+    ERROR_REL_RANGE = -6,       // |REL_*| code out of range.
   };
 
   // Key event |value| is not defined in <linux/input.h>.
@@ -87,6 +88,10 @@
   // Configure multitouch coordinate range.
   int ConfigureMultiTouchXY(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
 
+  // Configure a relative axis.
+  // @param rel_type One of the |REL_*| constants from <linux/input.h>.
+  int ConfigureRel(uint16_t rel_type);
+
   // Complete configuration and create the input device.
   int ConfigureEnd();
 
@@ -96,6 +101,7 @@
   int SendSynReport();
   int SendKey(uint16_t code, int32_t value);
   int SendAbs(uint16_t code, int32_t value);
+  int SendRel(uint16_t code, int32_t value);
   int SendMultiTouchSlot(int32_t slot);
   int SendMultiTouchXY(int32_t slot, int32_t id, int32_t x, int32_t y);
   int SendMultiTouchLift(int32_t slot);
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
index c7c8184..00e4ce6 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
@@ -60,6 +60,13 @@
     return service_->buttonState(touchpad, buttons).transactionError();
   }
 
+  status_t Scroll(int touchpad, float x, float y) override {
+    if (service_ == nullptr) {
+      return NO_INIT;
+    }
+    return service_->scroll(touchpad, x, y).transactionError();
+  }
+
   void dumpInternal(String8& result) override {
     result.append("[virtual touchpad]\n");
     result.appendFormat("connected = %s\n\n",
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index f0bdcd9..251ed0e 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -28,6 +28,12 @@
 static constexpr int32_t kHeight = 0x10000;
 static constexpr int32_t kSlots = 2;
 
+static constexpr float kScrollScale = 100.0f;
+
+int32_t scale_relative_scroll(float x) {
+  return kScrollScale * x;
+}
+
 }  // anonymous namespace
 
 std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
@@ -66,6 +72,8 @@
     touchpad.injector->ConfigureInputProperty(INPUT_PROP_DIRECT);
     touchpad.injector->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
     touchpad.injector->ConfigureAbsSlots(kSlots);
+    touchpad.injector->ConfigureRel(REL_WHEEL);
+    touchpad.injector->ConfigureRel(REL_HWHEEL);
     touchpad.injector->ConfigureKey(BTN_TOUCH);
     touchpad.injector->ConfigureKey(BTN_BACK);
     touchpad.injector->ConfigureEnd();
@@ -162,6 +170,33 @@
   return touchpad.injector->GetError();
 }
 
+int VirtualTouchpadEvdev::Scroll(int touchpad_id, float x, float y) {
+  if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
+    return EINVAL;
+  }
+  if ((x < -1.0f) || (x > 1.0f) || (y < -1.0f) || (y > 1.0f)) {
+    return EINVAL;
+  }
+  Touchpad& touchpad = touchpad_[touchpad_id];
+  if (!touchpad.injector) {
+    return EvdevInjector::ERROR_SEQUENCING;
+  }
+  touchpad.injector->ResetError();
+  const int32_t scaled_x = scale_relative_scroll(x);
+  const int32_t scaled_y = scale_relative_scroll(y);
+  ALOGV("(%f,%f) -> (%" PRId32 ",%" PRId32 ")", x, y, scaled_x, scaled_y);
+  if (scaled_x) {
+    touchpad.injector->SendRel(REL_HWHEEL, scaled_x);
+  }
+  if (scaled_y) {
+    touchpad.injector->SendRel(REL_WHEEL, scaled_y);
+  }
+  if (scaled_x || scaled_y) {
+    touchpad.injector->SendSynReport();
+  }
+  return touchpad.injector->GetError();
+}
+
 void VirtualTouchpadEvdev::dumpInternal(String8& result) {
   for (int i = 0; i < kTouchpads; ++i) {
     const auto& touchpad = touchpad_[i];
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
index 2fb8ff3..c9578bf 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -21,6 +21,7 @@
   status_t Detach() override;
   status_t Touch(int touchpad, float x, float y, float pressure) override;
   status_t ButtonState(int touchpad, int buttons) override;
+  status_t Scroll(int touchpad, float x, float y) override;
   void dumpInternal(String8& result) override;
 
  protected:
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index 81edd32..523f890 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -87,6 +87,16 @@
   return binder::Status::ok();
 }
 
+binder::Status VirtualTouchpadService::scroll(int touchpad, float x, float y) {
+  if (!CheckPermissions()) {
+    return binder::Status::fromStatusT(PERMISSION_DENIED);
+  }
+  if (const status_t error = touchpad_->Scroll(touchpad, x, y)) {
+    return binder::Status::fromStatusT(error);
+  }
+  return binder::Status::ok();
+}
+
 status_t VirtualTouchpadService::dump(
     int fd, const Vector<String16>& args[[gnu::unused]]) {
   String8 result;
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index cf236f9..2c46209 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -23,6 +23,7 @@
   binder::Status detach() override;
   binder::Status touch(int touchpad, float x, float y, float pressure) override;
   binder::Status buttonState(int touchpad, int buttons) override;
+  binder::Status scroll(int touchpad, float x, float y) override;
 
   // Implements BBinder::dump().
   status_t dump(int fd, const Vector<String16>& args) override;
diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
index 9cfb186..256203c 100644
--- a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
+++ b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
@@ -34,4 +34,15 @@
    * @param buttons A union of MotionEvent BUTTON_* values.
    */
   void buttonState(int touchpad, int buttons) = 3;
+
+  /**
+   * Generate a simulated scroll event.
+   *
+   * @param touchpad Selects touchpad.
+   * @param x Horizontal scroll increment.
+   * @param y Vertical scroll increment.
+   *
+   * Scroll values are in the range [-1.0, 1.0].
+   */
+  void scroll(int touchpad, float x, float y) = 4;
 }
diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc
new file mode 100644
index 0000000..205e8b9
--- /dev/null
+++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc
@@ -0,0 +1,26 @@
+# 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.
+
+#
+# Virtual touchpad for the primary display
+device.internal = 1
+
+touch.deviceType = touchScreen
+
+# Have input flinger treat injected scroll events like a G1 ball
+# rather than the default mouse wheel, because the latter requires
+# a visible pointer for targeting.
+device.type = rotaryEncoder
+device.res = 1.0e+2
+device.scalingFactor = 1.0e-2
diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
index 3728ef0..d9714e0 100644
--- a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
+++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
@@ -18,6 +18,13 @@
 
 touch.deviceType = touchScreen
 
+# Have input flinger treat injected scroll events like a G1 ball
+# rather than the default mouse wheel, because the latter requires
+# a visible pointer for targeting.
+device.type = rotaryEncoder
+device.res = 1.0e+2
+device.scalingFactor = 1.0e-2
+
 # This displayID matches the unique ID of the virtual display created for VR.
 # This will indicate to input flinger than it should link this input device
 # with the virtual display.
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
index da3a0b7..99b72fc 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpad.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
@@ -61,6 +61,16 @@
   //
   virtual status_t ButtonState(int touchpad, int buttons) = 0;
 
+  // Generate a simulated scroll event.
+  //
+  // @param touchpad Touchpad selector index.
+  // @param x Horizontal scroll increment.
+  // @param y Vertical scroll increment.
+  //            Values must be in the range [-1.0, 1.0].
+  // @returns OK on success.
+  //
+  virtual status_t Scroll(int touchpad, float x, float y) = 0;
+
   // Report state for 'dumpsys'.
   virtual void dumpInternal(String8& result) = 0;
 
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
index 23fb9f8..7d73f06 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
@@ -17,6 +17,7 @@
   status_t Detach() override;
   status_t Touch(int touchpad, float x, float y, float pressure) override;
   status_t ButtonState(int touchpad, int buttons) override;
+  status_t Scroll(int touchpad, float x, float y) override;
   void dumpInternal(String8& result) override;
 
  protected:
diff --git a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
index 15e6687..09fb1cc 100644
--- a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
+++ b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
@@ -61,6 +61,17 @@
 int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad,
                                   int buttons);
 
+// Generate a simulated scroll event.
+//
+// @param client Pointer to the virtual touchpad client.
+// @param touchpad Selects touchpad.
+// @param x Horizontal scroll increment.
+// @param y Vertical scroll increment.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x,
+                             float y);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index 564bcd7..b19b018 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -169,6 +169,11 @@
     expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
     // From ConfigureAbsSlots(kSlots):
     expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
+    // From ConfigureRel(REL_WHEEL):
+    expect.IoctlSetInt(UI_SET_EVBIT, EV_REL);
+    expect.IoctlSetInt(UI_SET_RELBIT, REL_WHEEL);
+    // From ConfigureRel(REL_HWHEEL):
+    expect.IoctlSetInt(UI_SET_RELBIT, REL_HWHEEL);
     // From ConfigureKey(BTN_TOUCH):
     expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
     expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);