Merge "Work on issue #36863299: [Fugu] CTS: PermissionFeatureTest failures:..." into oc-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 5421a75..5dad511 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1062,13 +1062,9 @@
     RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
                CommandOptions::WithTimeout(20).Build());
 
-    DumpFile("INTERRUPTS (1)", "/proc/interrupts");
-
     RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
                CommandOptions::WithTimeout(10).Build());
 
-    DumpFile("INTERRUPTS (2)", "/proc/interrupts");
-
     RunCommand("SYSTEM PROPERTIES", {"getprop"});
 
     RunCommand("VOLD DUMP", {"vdc", "dump"});
@@ -1152,6 +1148,13 @@
 
     RunDumpsys("APP PROVIDERS", {"activity", "provider", "all"});
 
+    printf("========================================================\n");
+    printf("== Dropbox crashes\n");
+    printf("========================================================\n");
+
+    RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
+    RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
+
     // DumpModemLogs adds the modem logs if available to the bugreport.
     // Do this at the end to allow for sufficient time for the modem logs to be
     // collected.
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index cc4144a..f5dca47 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -836,7 +836,7 @@
                 continue;
             }
 
-            if (!should_dump_hal_interface(info.interfaceName)) {
+            if (!should_dump_hal_interface(info.interfaceName.c_str())) {
                 continue;
             }
 
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index c604ca0..3e0f6f0 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -88,6 +88,7 @@
 static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
 static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
 static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 15;
+static constexpr int FLAG_FORCE = 1 << 16;
 
 namespace {
 
@@ -600,6 +601,113 @@
     return res;
 }
 
+static gid_t get_cache_gid(uid_t uid) {
+    int32_t gid = multiuser_get_cache_gid(multiuser_get_user_id(uid), multiuser_get_app_id(uid));
+    return (gid != -1) ? gid : uid;
+}
+
+binder::Status InstalldNativeService::fixupAppData(const std::unique_ptr<std::string>& uuid,
+        int32_t flags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    for (auto user : get_known_users(uuid_)) {
+        ATRACE_BEGIN("fixup user");
+        FTS* fts;
+        FTSENT* p;
+        char *argv[] = {
+                (char*) create_data_user_ce_path(uuid_, user).c_str(),
+                (char*) create_data_user_de_path(uuid_, user).c_str(),
+                nullptr
+        };
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+            return error("Failed to fts_open");
+        }
+        while ((p = fts_read(fts)) != nullptr) {
+            if (p->fts_info == FTS_D && p->fts_level == 1) {
+                // Track down inodes of cache directories
+                uint64_t raw = 0;
+                ino_t inode_cache = 0;
+                ino_t inode_code_cache = 0;
+                if (getxattr(p->fts_path, kXattrInodeCache, &raw, sizeof(raw)) == sizeof(raw)) {
+                    inode_cache = raw;
+                }
+                if (getxattr(p->fts_path, kXattrInodeCodeCache, &raw, sizeof(raw)) == sizeof(raw)) {
+                    inode_code_cache = raw;
+                }
+
+                // Figure out expected GID of each child
+                FTSENT* child = fts_children(fts, 0);
+                while (child != nullptr) {
+                    if ((child->fts_statp->st_ino == inode_cache)
+                            || (child->fts_statp->st_ino == inode_code_cache)
+                            || !strcmp(child->fts_name, "cache")
+                            || !strcmp(child->fts_name, "code_cache")) {
+                        child->fts_number = get_cache_gid(p->fts_statp->st_uid);
+                    } else {
+                        child->fts_number = p->fts_statp->st_uid;
+                    }
+                    child = child->fts_link;
+                }
+            } else if (p->fts_level >= 2) {
+                if (p->fts_level > 2) {
+                    // Inherit GID from parent once we're deeper into tree
+                    p->fts_number = p->fts_parent->fts_number;
+                }
+
+                uid_t uid = p->fts_parent->fts_statp->st_uid;
+                gid_t cache_gid = get_cache_gid(uid);
+                gid_t expected = p->fts_number;
+                gid_t actual = p->fts_statp->st_gid;
+                if (actual == expected) {
+#if FIXUP_DEBUG
+                    LOG(DEBUG) << "Ignoring " << p->fts_path << " with expected GID " << expected;
+#endif
+                    if (!(flags & FLAG_FORCE)) {
+                        fts_set(fts, p, FTS_SKIP);
+                    }
+                } else if ((actual == uid) || (actual == cache_gid)) {
+                    // Only consider fixing up when current GID belongs to app
+                    if (p->fts_info != FTS_D) {
+                        LOG(INFO) << "Fixing " << p->fts_path << " with unexpected GID " << actual
+                                << " instead of " << expected;
+                    }
+                    switch (p->fts_info) {
+                    case FTS_DP:
+                        // If we're moving towards cache GID, we need to set S_ISGID
+                        if (expected == cache_gid) {
+                            if (chmod(p->fts_path, 02771) != 0) {
+                                PLOG(WARNING) << "Failed to chmod " << p->fts_path;
+                            }
+                        }
+                        // Intentional fall through to also set GID
+                    case FTS_F:
+                        if (chown(p->fts_path, -1, expected) != 0) {
+                            PLOG(WARNING) << "Failed to chown " << p->fts_path;
+                        }
+                        break;
+                    case FTS_SL:
+                    case FTS_SLNONE:
+                        if (lchown(p->fts_path, -1, expected) != 0) {
+                            PLOG(WARNING) << "Failed to chown " << p->fts_path;
+                        }
+                        break;
+                    }
+                } else {
+                    // Ignore all other GID transitions, since they're kinda shady
+                    LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected GID " << actual
+                            << " instead of " << expected;
+                }
+            }
+        }
+        fts_close(fts);
+        ATRACE_END();
+    }
+    return ok();
+}
+
 binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
         const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
         const std::string& dataAppName, int32_t appId, const std::string& seInfo,
@@ -1044,6 +1152,9 @@
         }
     }
 
+#if HACK_FOR_37193650
+    extStats->dataSize = extStats->dataSize;
+#else
     int extGid = multiuser_get_ext_gid(userId, appId);
     if (extGid != -1) {
         if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
@@ -1058,6 +1169,7 @@
             extStats->dataSize += dq.dqb_curspace;
         }
     }
+#endif
 
     int sharedGid = multiuser_get_shared_gid(userId, appId);
     if (sharedGid != -1) {
@@ -1255,6 +1367,17 @@
         collectQuotaStats(device, userId, appId, &stats, &extStats);
         ATRACE_END();
 
+#if HACK_FOR_37193650
+        ATRACE_BEGIN("external");
+        for (size_t i = 0; i < packageNames.size(); i++) {
+            const char* pkgname = packageNames[i].c_str();
+            auto extPath = create_data_media_package_path(uuid_, userId, "data", pkgname);
+            calculate_tree_size(extPath, &extStats.dataSize);
+            auto mediaPath = create_data_media_package_path(uuid_, userId, "media", pkgname);
+            calculate_tree_size(mediaPath, &extStats.dataSize);
+        }
+        ATRACE_END();
+#endif
     } else {
         ATRACE_BEGIN("code");
         for (auto codePath : codePaths) {
@@ -1339,6 +1462,12 @@
         flags &= ~FLAG_USE_QUOTA;
     }
 
+#if HACK_FOR_37193650
+    if (userId != 0) {
+        flags &= ~FLAG_USE_QUOTA;
+    }
+#endif
+
     if (flags & FLAG_USE_QUOTA) {
         struct dqblk dq;
 
@@ -1400,6 +1529,7 @@
         for (auto appId : appIds) {
             if (appId >= AID_APP_START) {
                 collectQuotaStats(device, userId, appId, &stats, &extStats);
+
 #if MEASURE_DEBUG
                 // Sleep to make sure we don't lose logs
                 usleep(1);
@@ -1621,7 +1751,8 @@
         const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
         int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
         const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
-        const std::unique_ptr<std::string>& sharedLibraries) {
+        const std::unique_ptr<std::string>& sharedLibraries,
+        const std::unique_ptr<std::string>& seInfo) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     if (packageName && *packageName != "*") {
@@ -1636,9 +1767,9 @@
     const char* compiler_filter = compilerFilter.c_str();
     const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
     const char* shared_libraries = sharedLibraries ? sharedLibraries->c_str() : nullptr;
-
+    const char* se_info = seInfo ? seInfo->c_str() : nullptr;
     int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
-            oat_dir, dexFlags, compiler_filter, volume_uuid, shared_libraries);
+            oat_dir, dexFlags, compiler_filter, volume_uuid, shared_libraries, se_info);
     return res ? error(res, "Failed to dexopt") : ok();
 }
 
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 7ad8687..fe8aa14 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -58,6 +58,8 @@
     binder::Status destroyAppData(const std::unique_ptr<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode);
 
+    binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);
+
     binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
             const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
             int32_t appId, const std::vector<int64_t>& ceDataInodes,
@@ -80,7 +82,8 @@
             const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
             int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
             const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
-            const std::unique_ptr<std::string>& sharedLibraries);
+            const std::unique_ptr<std::string>& sharedLibraries,
+            const std::unique_ptr<std::string>& seInfo);
 
     binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
 
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 4195a01..e738b81 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -32,6 +32,8 @@
     void destroyAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
             int userId, int flags, long ceDataInode);
 
+    void fixupAppData(@nullable @utf8InCpp String uuid, int flags);
+
     long[] getAppSize(@nullable @utf8InCpp String uuid, in @utf8InCpp String[] packageNames,
             int userId, int flags, int appId, in long[] ceDataInodes,
             in @utf8InCpp String[] codePaths);
@@ -48,7 +50,8 @@
             @utf8InCpp String instructionSet, int dexoptNeeded,
             @nullable @utf8InCpp String outputPath, int dexFlags,
             @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
-            @nullable @utf8InCpp String sharedLibraries);
+            @nullable @utf8InCpp String sharedLibraries,
+            @nullable @utf8InCpp String seInfo);
 
     void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index f7e8d13..63afdcd 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -36,6 +36,7 @@
 #include <cutils/sched_policy.h>
 #include <log/log.h>               // TODO: Move everything to base/logging.
 #include <private/android_filesystem_config.h>
+#include <selinux/android.h>
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
@@ -1302,17 +1303,9 @@
     }
     std::string dex_dir = dex_path.substr(0, dirIndex);
 
-    // Assign the gid to the cache gid so that the oat file storage
-    // is counted towards the app cache.
-    int32_t cache_gid = multiuser_get_cache_gid(
-            multiuser_get_user_id(uid), multiuser_get_app_id(uid));
-    // If UID doesn't have a specific cache GID, use UID value
-    if (cache_gid == -1) {
-        cache_gid = uid;
-    }
-
     // Create oat file output directory.
-    if (prepare_app_cache_dir(dex_dir, "oat", 02711, uid, cache_gid) != 0) {
+    mode_t oat_dir_mode = S_IRWXU | S_IRWXG | S_IXOTH;
+    if (prepare_app_cache_dir(dex_dir, "oat", oat_dir_mode, uid, uid) != 0) {
         LOG(ERROR) << "Could not prepare oat dir for secondary dex: " << dex_path;
         return false;
     }
@@ -1322,7 +1315,7 @@
     oat_dir_out->assign(oat_dir);
 
     // Create oat/isa output directory.
-    if (prepare_app_cache_dir(*oat_dir_out, instruction_set, 02711, uid, cache_gid) != 0) {
+    if (prepare_app_cache_dir(*oat_dir_out, instruction_set, oat_dir_mode, uid, uid) != 0) {
         LOG(ERROR) << "Could not prepare oat/isa dir for secondary dex: " << dex_path;
         return false;
     }
@@ -1366,12 +1359,15 @@
 // Processes the dex_path as a secondary dex files and return true if the path dex file should
 // be compiled. Returns false for errors (logged) or true if the secondary dex path was process
 // successfully.
-// When returning true, dexopt_needed_out is assigned a valid OatFileAsssitant::DexOptNeeded
-// code and oat_dir_out is assigned the oat dir path where the oat file should be stored.
+// When returning true, the output parameters will be:
+//   - is_public_out: whether or not the oat file should not be made public
+//   - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded
+//   - oat_dir_out: the oat dir path where the oat file should be stored
+//   - dex_path_out: the real path of the dex file
 static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname,
         int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
-        const char* compiler_filter, int* dexopt_needed_out, std::string* oat_dir_out,
-        std::string* dex_path_out) {
+        const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
+        std::string* oat_dir_out, std::string* dex_path_out) {
     int storage_flag;
 
     if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
@@ -1407,7 +1403,8 @@
     }
 
     // Check if the path exist. If not, there's nothing to do.
-    if (access(dex_path.c_str(), F_OK) != 0) {
+    struct stat dex_path_stat;
+    if (stat(dex_path.c_str(), &dex_path_stat) != 0) {
         if (errno == ENOENT) {
             // Secondary dex files might be deleted any time by the app.
             // Nothing to do if that's the case
@@ -1418,6 +1415,11 @@
         }
     }
 
+    // Check if we should make the oat file public.
+    // Note that if the dex file is not public the compiled code cannot be made public.
+    *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) &&
+            ((dex_path_stat.st_mode & S_IROTH) != 0);
+
     // Prepare the oat directories.
     if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set, oat_dir_out)) {
         return false;
@@ -1458,14 +1460,14 @@
 
 int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
-        const char* volume_uuid, const char* shared_libraries) {
+        const char* volume_uuid, const char* shared_libraries, const char* se_info) {
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
     if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
         LOG_FATAL("dexopt flags contains unknown fields\n");
     }
 
-    bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
+    bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
     bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
     bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
     bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
@@ -1477,7 +1479,8 @@
     std::string dex_real_path;
     if (is_secondary_dex) {
         if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
-                instruction_set, compiler_filter, &dexopt_needed, &oat_dir_str, &dex_real_path)) {
+                instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
+                &dex_real_path)) {
             oat_dir = oat_dir_str.c_str();
             dex_path = dex_real_path.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
@@ -1516,6 +1519,19 @@
         return -1;
     }
 
+    // Ensure that the oat dir and the compiler artifacts of secondary dex files have the correct
+    // selinux context (we generate them on the fly during the dexopt invocation and they don't
+    // fully inherit their parent context).
+    // Note that for primary apk the oat files are created before, in a separate installd
+    // call which also does the restorecon. TODO(calin): unify the paths.
+    if (is_secondary_dex) {
+        if (selinux_android_restorecon_pkgdir(oat_dir, se_info, uid,
+                SELINUX_ANDROID_RESTORECON_RECURSE)) {
+            LOG(ERROR) << "Failed to restorecon " << oat_dir;
+            return -1;
+        }
+    }
+
     // Create a swap file if necessary.
     unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
 
@@ -1857,8 +1873,9 @@
                   atoi(params[6]),              // dexopt_flags
                   params[7],                    // compiler_filter
                   parse_null(params[8]),        // volume_uuid
-                  parse_null(params[9]));       // shared_libraries
-    static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param count");
+                  parse_null(params[9]),        // shared_libraries
+                  parse_null(params[10]));       // se_info
+    static_assert(DEXOPT_PARAM_COUNT == 11U, "Unexpected dexopt param count");
 }
 
 }  // namespace installd
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index dbf3fae..88144b7 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -60,10 +60,10 @@
 
 int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
-        const char* volume_uuid, const char* shared_libraries);
+        const char* volume_uuid, const char* shared_libraries, const char* se_info);
 
-static constexpr size_t DEXOPT_PARAM_COUNT = 10U;
-static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param size");
+static constexpr size_t DEXOPT_PARAM_COUNT = 11U;
+static_assert(DEXOPT_PARAM_COUNT == 11U, "Unexpected dexopt param size");
 
 // Helper for the above, converting arguments.
 int dexopt(const char* const params[DEXOPT_PARAM_COUNT]);
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index b5b080d..630c1f3 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -33,3 +33,22 @@
         "libdiskusage",
     ],
 }
+
+cc_test {
+    name: "installd_service_test",
+    clang: true,
+    srcs: ["installd_service_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "liblogwrap",
+        "libselinux",
+        "libutils",
+    ],
+    static_libs: [
+        "libinstalld",
+        "libdiskusage",
+    ],
+}
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
new file mode 100644
index 0000000..4a1f333
--- /dev/null
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/statvfs.h>
+#include <sys/xattr.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+constexpr const char* kTestUuid = "TEST";
+
+static constexpr int FLAG_FORCE = 1 << 16;
+
+int get_property(const char *key, char *value, const char *default_value) {
+    return property_get(key, value, default_value);
+}
+
+bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *oat_dir ATTRIBUTE_UNUSED,
+        const char *apk_path ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *apk_path ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *src ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    ::mkdir(fullPath, mode);
+    ::chown(fullPath, owner, group);
+    ::chmod(fullPath, mode);
+}
+
+static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
+    int fd = ::open(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(),
+            O_RDWR | O_CREAT, mode);
+    ::fchown(fd, owner, group);
+    ::fchmod(fd, mode);
+    ::close(fd);
+}
+
+static int stat_gid(const char* path) {
+    struct stat buf;
+    ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf);
+    return buf.st_gid;
+}
+
+static int stat_mode(const char* path) {
+    struct stat buf;
+    ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf);
+    return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
+}
+
+class ServiceTest : public testing::Test {
+protected:
+    InstalldNativeService* service;
+    std::unique_ptr<std::string> testUuid;
+
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
+
+        service = new InstalldNativeService();
+        testUuid = std::make_unique<std::string>();
+        *testUuid = std::string(kTestUuid);
+        system("mkdir -p /data/local/tmp/user/0");
+    }
+
+    virtual void TearDown() {
+        delete service;
+        system("rm -rf /data/local/tmp/user");
+    }
+};
+
+TEST_F(ServiceTest, FixupAppData_Upgrade) {
+    LOG(INFO) << "FixupAppData_Upgrade";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/normal", 10000, 10000, 0700);
+    mkdir("com.example/cache", 10000, 10000, 0700);
+    touch("com.example/cache/file", 10000, 10000, 0700);
+
+    service->fixupAppData(testUuid, 0);
+
+    EXPECT_EQ(10000, stat_gid("com.example/normal"));
+    EXPECT_EQ(20000, stat_gid("com.example/cache"));
+    EXPECT_EQ(20000, stat_gid("com.example/cache/file"));
+
+    EXPECT_EQ(0700, stat_mode("com.example/normal"));
+    EXPECT_EQ(02771, stat_mode("com.example/cache"));
+    EXPECT_EQ(0700, stat_mode("com.example/cache/file"));
+}
+
+TEST_F(ServiceTest, FixupAppData_Moved) {
+    LOG(INFO) << "FixupAppData_Moved";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0700);
+    mkdir("com.example/bar", 10000, 20000, 0700);
+    touch("com.example/bar/file", 10000, 20000, 0700);
+
+    service->fixupAppData(testUuid, 0);
+
+    EXPECT_EQ(10000, stat_gid("com.example/foo"));
+    EXPECT_EQ(20000, stat_gid("com.example/foo/file"));
+    EXPECT_EQ(10000, stat_gid("com.example/bar"));
+    EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+
+    service->fixupAppData(testUuid, FLAG_FORCE);
+
+    EXPECT_EQ(10000, stat_gid("com.example/foo"));
+    EXPECT_EQ(10000, stat_gid("com.example/foo/file"));
+    EXPECT_EQ(10000, stat_gid("com.example/bar"));
+    EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 24c0b45..c792082 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -1047,18 +1047,18 @@
     while ((p = fts_read(fts)) != NULL) {
         switch (p->fts_info) {
         case FTS_DP:
-            if (chmod(p->fts_accpath, target_mode) != 0) {
+            if (chmod(p->fts_path, target_mode) != 0) {
                 PLOG(WARNING) << "Failed to chmod " << p->fts_path;
             }
             // Intentional fall through to also set GID
         case FTS_F:
-            if (chown(p->fts_accpath, -1, gid) != 0) {
+            if (chown(p->fts_path, -1, gid) != 0) {
                 PLOG(WARNING) << "Failed to chown " << p->fts_path;
             }
             break;
         case FTS_SL:
         case FTS_SLNONE:
-            if (lchown(p->fts_accpath, -1, gid) != 0) {
+            if (lchown(p->fts_path, -1, gid) != 0) {
                 PLOG(WARNING) << "Failed to chown " << p->fts_path;
             }
             break;
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 7ebfea2..5db547e 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -31,6 +31,8 @@
 #include <installd_constants.h>
 
 #define MEASURE_DEBUG 0
+#define FIXUP_DEBUG 0
+#define HACK_FOR_37193650 1
 
 namespace android {
 namespace installd {
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 420ec3c..4c57361 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -301,7 +301,6 @@
                 if (!manifest.add(vintf::ManifestHal{
                     .format = vintf::HalFormat::HIDL,
                     .name = fqName.package(),
-                    .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""},
                     .transportArch = {transport, arch}
                 })) {
                     mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
index 8cffb3c..b703ed4 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -9,5 +9,18 @@
     ],
 
     cflags: ["-DXP_UNIX"],
-    //shared_libs: ["librt"],
+}
+
+cc_binary {
+    name: "vndservice",
+
+    proprietary: true,
+    srcs: ["service.cpp"],
+
+    shared_libs: [
+        "libutils",
+        "libbinder",
+    ],
+
+    cflags: ["-DXP_UNIX", "-DVENDORSERVICES"],
 }
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 428b87c..bc11256 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -68,13 +68,6 @@
 
 int main(int argc, char* const argv[])
 {
-    sp<IServiceManager> sm = defaultServiceManager();
-    fflush(stdout);
-    if (sm == NULL) {
-        aerr << "service: Unable to get default service manager!" << endl;
-        return 20;
-    }
-    
     bool wantsUsage = false;
     int result = 0;
     
@@ -95,6 +88,15 @@
             break;
         }
     }
+#ifdef VENDORSERVICES
+    ProcessState::initWithDriver("/dev/vndbinder");
+#endif
+    sp<IServiceManager> sm = defaultServiceManager();
+    fflush(stdout);
+    if (sm == NULL) {
+        aerr << "service: Unable to get default service manager!" << endl;
+        return 20;
+    }
     
     if (optind >= argc) {
         wantsUsage = true;
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 5431233..68d39db 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -43,6 +43,9 @@
         "service_manager.c",
         "binder.c",
     ],
+    cflags: [
+        "-DVENDORSERVICEMANAGER=1",
+    ],
     shared_libs: ["libcutils", "libselinux"],
     init_rc: ["vndservicemanager.rc"],
 }
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 5d44e87..1f56a47 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -17,13 +17,12 @@
 
 #include "binder.h"
 
-#if 0
-#define ALOGI(x...) fprintf(stderr, "svcmgr: " x)
-#define ALOGE(x...) fprintf(stderr, "svcmgr: " x)
+#ifdef VENDORSERVICEMANAGER
+#define LOG_TAG "VendorServiceManager"
 #else
 #define LOG_TAG "ServiceManager"
-#include <log/log.h>
 #endif
+#include <log/log.h>
 
 struct audit_data {
     pid_t pid;
@@ -66,7 +65,11 @@
 static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
 {
     char *sctx = NULL;
+#ifdef VENDORSERVICEMANAGER
+    const char *class = "vndservice_manager";
+#else
     const char *class = "service_manager";
+#endif
     bool allowed;
     struct audit_data ad;
 
@@ -374,7 +377,14 @@
 
     bs = binder_open(driver, 128*1024);
     if (!bs) {
+#ifdef VENDORSERVICEMANAGER
+        ALOGW("failed to open binder driver %s\n", driver);
+        while (true) {
+            sleep(UINT_MAX);
+        }
+#else
         ALOGE("failed to open binder driver %s\n", driver);
+#endif
         return -1;
     }
 
@@ -388,7 +398,11 @@
     cb.func_log = selinux_log_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
+#ifdef VENDORSERVICEMANAGER
+    sehandle = selinux_android_vendor_service_context_handle();
+#else
     sehandle = selinux_android_service_context_handle();
+#endif
     selinux_status_open(true);
 
     if (sehandle == NULL) {
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index aee7bd8..aec211a 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -1,5 +1,5 @@
 service servicemanager /system/bin/servicemanager
-    class core
+    class core animation
     user system
     group system readproc
     critical
@@ -12,4 +12,3 @@
     onrestart restart drm
     onrestart restart cameraserver
     writepid /dev/cpuset/system-background/tasks
-
diff --git a/data/etc/android.software.activities_on_secondary_displays.xml b/data/etc/android.software.activities_on_secondary_displays.xml
new file mode 100644
index 0000000..db1bdb5
--- /dev/null
+++ b/data/etc/android.software.activities_on_secondary_displays.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<permissions>
+    <feature name="android.software.activities_on_secondary_displays" />
+</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index b5287ac..9229f82 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -46,6 +46,7 @@
     <feature name="android.software.home_screen" />
     <feature name="android.software.input_methods" />
     <feature name="android.software.picture_in_picture" />
+    <feature name="android.software.activities_on_secondary_displays" />
     <feature name="android.software.print" />
     <feature name="android.software.companion_device_setup" />
 
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 51ea1ca..64e32ff 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -46,6 +46,7 @@
     <feature name="android.software.home_screen" />
     <feature name="android.software.input_methods" />
     <feature name="android.software.picture_in_picture" />
+    <feature name="android.software.activities_on_secondary_displays" />
     <feature name="android.software.print" />
     <feature name="android.software.companion_device_setup" />
 
diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h
index 1ec2a67..23b39aa 100644
--- a/include/android/native_window_jni.h
+++ b/include/android/native_window_jni.h
@@ -54,6 +54,17 @@
 ANativeWindow* ANativeWindow_fromSurfaceTexture(JNIEnv* env, jobject surfaceTexture);
 #endif
 
+#if __ANDROID_API__ >= 26
+/**
+ * Return a Java Surface object derived from the ANativeWindow, for interacting
+ * with it through Java code. The returned Java object acquires a reference on
+ * the ANativeWindow; maintains it through general Java object's life cycle;
+ * and will automatically release the reference when the Java object gets garbage
+ * collected.
+ */
+jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window);
+#endif
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index cb9b373..9557b4f 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -32,9 +32,12 @@
 
 // ----------------------------------------------------------------------------
 
-class BitTube;
 class IDisplayEventConnection;
 
+namespace gui {
+class BitTube;
+} // namespace gui
+
 static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) {
     return static_cast<uint32_t>(c1) << 24 |
         static_cast<uint32_t>(c2) << 16 |
@@ -108,15 +111,13 @@
      * should be destroyed and getEvents() shouldn't be called again.
      */
     ssize_t getEvents(Event* events, size_t count);
-    static ssize_t getEvents(const sp<BitTube>& dataChannel,
-            Event* events, size_t count);
+    static ssize_t getEvents(gui::BitTube* dataChannel, Event* events, size_t count);
 
     /*
      * sendEvents write events to the queue and returns how many events were
      * written.
      */
-    static ssize_t sendEvents(const sp<BitTube>& dataChannel,
-            Event const* events, size_t count);
+    static ssize_t sendEvents(gui::BitTube* dataChannel, Event const* events, size_t count);
 
     /*
      * setVsyncRate() sets the Event::VSync delivery rate. A value of
@@ -134,7 +135,7 @@
 
 private:
     sp<IDisplayEventConnection> mEventConnection;
-    sp<BitTube> mDataChannel;
+    std::unique_ptr<gui::BitTube> mDataChannel;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 51d7666..2cf6162 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -23,6 +23,7 @@
 #include <gui/BufferQueueDefs.h>
 #include <gui/ConsumerBase.h>
 
+#include <ui/FenceTime.h>
 #include <ui/GraphicBuffer.h>
 
 #include <utils/String8.h>
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index a3c7d64..c082882 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -14,103 +14,84 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GUI_ICONSUMERLISTENER_H
-#define ANDROID_GUI_ICONSUMERLISTENER_H
+#pragma once
 
-#include <stdint.h>
-#include <sys/types.h>
+#include <binder/IInterface.h>
+#include <binder/SafeInterface.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
-#include <binder/IInterface.h>
-
-#include <gui/FrameTimestamps.h>
+#include <cstdint>
 
 namespace android {
-// ----------------------------------------------------------------------------
 
 class BufferItem;
+class FrameEventHistoryDelta;
+struct NewFrameEventsEntry;
 
-// ConsumerListener is the interface through which the BufferQueue notifies
-// the consumer of events that the consumer may wish to react to.  Because
-// the consumer will generally have a mutex that is locked during calls from
-// the consumer to the BufferQueue, these calls from the BufferQueue to the
+// ConsumerListener is the interface through which the BufferQueue notifies the consumer of events
+// that the consumer may wish to react to. Because the consumer will generally have a mutex that is
+// locked during calls from the consumer to the BufferQueue, these calls from the BufferQueue to the
 // consumer *MUST* be called only when the BufferQueue mutex is NOT locked.
 
 class ConsumerListener : public virtual RefBase {
 public:
-    ConsumerListener() { }
+    ConsumerListener() {}
     virtual ~ConsumerListener();
 
     // onDisconnect is called when a producer disconnects from the BufferQueue.
     virtual void onDisconnect() {} /* Asynchronous */
 
-    // onFrameAvailable is called from queueBuffer each time an additional
-    // frame becomes available for consumption. This means that frames that
-    // are queued while in asynchronous mode only trigger the callback if no
-    // previous frames are pending. Frames queued while in synchronous mode
-    // always trigger the callback. The item passed to the callback will contain
-    // all of the information about the queued frame except for its
-    // GraphicBuffer pointer, which will always be null (except if the consumer
-    // is SurfaceFlinger).
+    // onFrameAvailable is called from queueBuffer each time an additional frame becomes available
+    // for consumption. This means that frames that are queued while in asynchronous mode only
+    // trigger the callback if no previous frames are pending. Frames queued while in synchronous
+    // mode always trigger the callback. The item passed to the callback will contain all of the
+    // information about the queued frame except for its GraphicBuffer pointer, which will always be
+    // null (except if the consumer is SurfaceFlinger).
     //
-    // This is called without any lock held and can be called concurrently
-    // by multiple threads.
+    // This is called without any lock held and can be called concurrently by multiple threads.
     virtual void onFrameAvailable(const BufferItem& item) = 0; /* Asynchronous */
 
-    // onFrameReplaced is called from queueBuffer if the frame being queued is
-    // replacing an existing slot in the queue. Any call to queueBuffer that
-    // doesn't call onFrameAvailable will call this callback instead. The item
-    // passed to the callback will contain all of the information about the
-    // queued frame except for its GraphicBuffer pointer, which will always be
-    // null.
+    // onFrameReplaced is called from queueBuffer if the frame being queued is replacing an existing
+    // slot in the queue. Any call to queueBuffer that doesn't call onFrameAvailable will call this
+    // callback instead. The item passed to the callback will contain all of the information about
+    // the queued frame except for its GraphicBuffer pointer, which will always be null.
     //
-    // This is called without any lock held and can be called concurrently
-    // by multiple threads.
+    // This is called without any lock held and can be called concurrently by multiple threads.
     virtual void onFrameReplaced(const BufferItem& /* item */) {} /* Asynchronous */
 
-    // onBuffersReleased is called to notify the buffer consumer that the
-    // BufferQueue has released its references to one or more GraphicBuffers
-    // contained in its slots.  The buffer consumer should then call
-    // BufferQueue::getReleasedBuffers to retrieve the list of buffers
+    // onBuffersReleased is called to notify the buffer consumer that the BufferQueue has released
+    // its references to one or more GraphicBuffers contained in its slots. The buffer consumer
+    // should then call BufferQueue::getReleasedBuffers to retrieve the list of buffers.
     //
-    // This is called without any lock held and can be called concurrently
-    // by multiple threads.
+    // This is called without any lock held and can be called concurrently by multiple threads.
     virtual void onBuffersReleased() = 0; /* Asynchronous */
 
-    // onSidebandStreamChanged is called to notify the buffer consumer that the
-    // BufferQueue's sideband buffer stream has changed. This is called when a
-    // stream is first attached and when it is either detached or replaced by a
-    // different stream.
+    // onSidebandStreamChanged is called to notify the buffer consumer that the BufferQueue's
+    // sideband buffer stream has changed. This is called when a stream is first attached and when
+    // it is either detached or replaced by a different stream.
     virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
 
-    // Notifies the consumer of any new producer-side timestamps and
-    // returns the combined frame history that hasn't already been retrieved.
-    virtual void addAndGetFrameTimestamps(
-            const NewFrameEventsEntry* /*newTimestamps*/,
-            FrameEventHistoryDelta* /*outDelta*/) {}
+    // Notifies the consumer of any new producer-side timestamps and returns the combined frame
+    // history that hasn't already been retrieved.
+    //
+    // WARNING: This method can only be called when the BufferQueue is in the consumer's process.
+    virtual void addAndGetFrameTimestamps(const NewFrameEventsEntry* /*newTimestamps*/,
+                                          FrameEventHistoryDelta* /*outDelta*/) {}
 };
 
-
-class IConsumerListener : public ConsumerListener, public IInterface
-{
+class IConsumerListener : public ConsumerListener, public IInterface {
 public:
     DECLARE_META_INTERFACE(ConsumerListener)
 };
 
-// ----------------------------------------------------------------------------
-
-class BnConsumerListener : public BnInterface<IConsumerListener>
-{
+class BnConsumerListener : public SafeBnInterface<IConsumerListener> {
 public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
+    BnConsumerListener() : SafeBnInterface<IConsumerListener>("BnConsumerListener") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
 };
 
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_ICONSUMERLISTENER_H
+} // namespace android
diff --git a/include/gui/IDisplayEventConnection.h b/include/gui/IDisplayEventConnection.h
index 848368c..d783f74 100644
--- a/include/gui/IDisplayEventConnection.h
+++ b/include/gui/IDisplayEventConnection.h
@@ -14,60 +14,52 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GUI_IDISPLAY_EVENT_CONNECTION_H
-#define ANDROID_GUI_IDISPLAY_EVENT_CONNECTION_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
+#pragma once
 
 #include <binder/IInterface.h>
+#include <binder/SafeInterface.h>
+
+#include <utils/Errors.h>
+
+#include <cstdint>
 
 namespace android {
-// ----------------------------------------------------------------------------
 
+namespace gui {
 class BitTube;
+} // namespace gui
 
-class IDisplayEventConnection : public IInterface
-{
+class IDisplayEventConnection : public IInterface {
 public:
-
     DECLARE_META_INTERFACE(DisplayEventConnection)
 
     /*
-     * getDataChannel() returns a BitTube where to receive the events from
+     * stealReceiveChannel() returns a BitTube to receive events from. Only the receive file
+     * descriptor of outChannel will be initialized, and this effectively "steals" the receive
+     * channel from the remote end (such that the remote end can only use its send channel).
      */
-    virtual sp<BitTube> getDataChannel() const = 0;
+    virtual status_t stealReceiveChannel(gui::BitTube* outChannel) = 0;
 
     /*
-     * setVsyncRate() sets the vsync event delivery rate. A value of
-     * 1 returns every vsync events. A value of 2 returns every other events,
-     * etc... a value of 0 returns no event unless  requestNextVsync() has
-     * been called.
+     * setVsyncRate() sets the vsync event delivery rate. A value of 1 returns every vsync event.
+     * A value of 2 returns every other event, etc. A value of 0 returns no event unless
+     * requestNextVsync() has been called.
      */
-    virtual void setVsyncRate(uint32_t count) = 0;
+    virtual status_t setVsyncRate(uint32_t count) = 0;
 
     /*
-     * requestNextVsync() schedules the next vsync event. It has no effect
-     * if the vsync rate is > 0.
+     * requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0.
      */
-    virtual void requestNextVsync() = 0;    // asynchronous
+    virtual void requestNextVsync() = 0; // Asynchronous
 };
 
-// ----------------------------------------------------------------------------
-
-class BnDisplayEventConnection : public BnInterface<IDisplayEventConnection>
-{
+class BnDisplayEventConnection : public SafeBnInterface<IDisplayEventConnection> {
 public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
+    BnDisplayEventConnection()
+          : SafeBnInterface<IDisplayEventConnection>("BnDisplayEventConnection") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
 };
 
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_IDISPLAY_EVENT_CONNECTION_H
+} // namespace android
diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index a680bc6..2c613ea 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -29,14 +29,6 @@
 public:
     DECLARE_META_INTERFACE(SurfaceComposerClient)
 
-    enum class Tag : uint32_t {
-        CreateSurface = IBinder::FIRST_CALL_TRANSACTION,
-        DestroySurface,
-        ClearLayerFrameStats,
-        GetLayerFrameStats,
-        Last,
-    };
-
     // flags for createSurface()
     enum { // (keep in sync with Surface.java)
         eHidden = 0x00000004,
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 62f6cad..88ef010 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -257,10 +257,25 @@
     virtual int query(int what, int* value) const;
 
     virtual int connect(int api, const sp<IProducerListener>& listener);
+
+    // When reportBufferRemoval is true, clients must call getAndFlushRemovedBuffers to fetch
+    // GraphicBuffers removed from this surface after a dequeueBuffer, detachNextBuffer or
+    // attachBuffer call. This allows clients with their own buffer caches to free up buffers no
+    // longer in use by this surface.
+    virtual int connect(
+            int api, const sp<IProducerListener>& listener,
+            bool reportBufferRemoval);
     virtual int detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence);
     virtual int attachBuffer(ANativeWindowBuffer*);
 
+    // When client connects to Surface with reportBufferRemoval set to true, any buffers removed
+    // from this Surface will be collected and returned here. Once this method returns, these
+    // buffers will no longer be referenced by this Surface unless they are attached to this
+    // Surface later. The list of removed buffers will only be stored until the next dequeueBuffer,
+    // detachNextBuffer, or attachBuffer call.
+    status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out);
+
 protected:
     enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
@@ -414,6 +429,9 @@
     // A cached copy of the FrameEventHistory maintained by the consumer.
     bool mEnableFrameTimestamps = false;
     std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
+
+    bool mReportRemovedBuffers = false;
+    std::vector<sp<GraphicBuffer>> mRemovedBuffers;
 };
 
 } // namespace android
diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h
index 6b21979..56d7cc8 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/include/media/openmax/OMX_AsString.h
@@ -557,6 +557,7 @@
         case OMX_IndexConfigPriority:                   return "ConfigPriority";
         case OMX_IndexConfigOperatingRate:              return "ConfigOperatingRate";
         case OMX_IndexParamConsumerUsageBits:           return "ParamConsumerUsageBits";
+        case OMX_IndexConfigLatency:                    return "ConfigLatency";
         default:                                        return asString((OMX_INDEXTYPE)i, def);
     }
 }
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index eccecaa..5a029d0 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -96,6 +96,7 @@
     OMX_IndexConfigPriority,                        /**< reference: OMX_PARAM_U32TYPE */
     OMX_IndexConfigOperatingRate,                   /**< reference: OMX_PARAM_U32TYPE in Q16 format for video and in Hz for audio */
     OMX_IndexParamConsumerUsageBits,                /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigLatency,                         /**< reference: OMX_PARAM_U32TYPE */
     OMX_IndexExtOtherEndUnused,
 
     /* Time configurations */
diff --git a/include/private/gui/BitTube.h b/include/private/gui/BitTube.h
deleted file mode 100644
index 9d65fad..0000000
--- a/include/private/gui/BitTube.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GUI_SENSOR_CHANNEL_H
-#define ANDROID_GUI_SENSOR_CHANNEL_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-class Parcel;
-
-class BitTube : public RefBase
-{
-public:
-
-    // creates a BitTube with a default (4KB) send buffer
-    BitTube();
-
-    // creates a BitTube with a a specified send and receive buffer size
-    explicit BitTube(size_t bufsize);
-
-    explicit BitTube(const Parcel& data);
-    virtual ~BitTube();
-
-    // check state after construction
-    status_t initCheck() const;
-
-    // get receive file-descriptor
-    int getFd() const;
-
-    // get the send file-descriptor.
-    int getSendFd() const;
-
-    // send objects (sized blobs). All objects are guaranteed to be written or the call fails.
-    template <typename T>
-    static ssize_t sendObjects(const sp<BitTube>& tube,
-            T const* events, size_t count) {
-        return sendObjects(tube, events, count, sizeof(T));
-    }
-
-    // receive objects (sized blobs). If the receiving buffer isn't large enough,
-    // excess messages are silently discarded.
-    template <typename T>
-    static ssize_t recvObjects(const sp<BitTube>& tube,
-            T* events, size_t count) {
-        return recvObjects(tube, events, count, sizeof(T));
-    }
-
-    // parcels this BitTube
-    status_t writeToParcel(Parcel* reply) const;
-
-private:
-    void init(size_t rcvbuf, size_t sndbuf);
-
-    // send a message. The write is guaranteed to send the whole message or fail.
-    ssize_t write(void const* vaddr, size_t size);
-
-    // receive a message. the passed buffer must be at least as large as the
-    // write call used to send the message, excess data is silently discarded.
-    ssize_t read(void* vaddr, size_t size);
-
-    int mSendFd;
-    mutable int mReceiveFd;
-
-    static ssize_t sendObjects(const sp<BitTube>& tube,
-            void const* events, size_t count, size_t objSize);
-
-    static ssize_t recvObjects(const sp<BitTube>& tube,
-            void* events, size_t count, size_t objSize);
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_SENSOR_CHANNEL_H
diff --git a/include/ui/DebugUtils.h b/include/ui/DebugUtils.h
new file mode 100644
index 0000000..8483808
--- /dev/null
+++ b/include/ui/DebugUtils.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <system/graphics.h>
+
+#include <string>
+
+std::string decodeStandard(android_dataspace dataspace);
+std::string decodeTransfer(android_dataspace dataspace);
+std::string decodeRange(android_dataspace dataspace);
+std::string dataspaceDetails(android_dataspace dataspace);
+std::string decodeColorMode(android_color_mode colormode);
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 040d1e7..af1d8be 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -72,30 +72,69 @@
         USAGE_CURSOR            = GRALLOC_USAGE_CURSOR,
     };
 
+    static sp<GraphicBuffer> from(ANativeWindowBuffer *);
+
+
+    // Create a GraphicBuffer to be unflatten'ed into or be reallocated.
     GraphicBuffer();
 
-    // creates w * h buffer
-    GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
-            uint32_t inUsage, std::string requestorName = "<Unknown>");
-
-    // creates w * h buffer with a layer count using gralloc1
+    // Create a GraphicBuffer by allocating and managing a buffer internally.
+    // This function is privileged.  See reallocate for details.
     GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
             uint32_t inLayerCount, uint64_t inProducerUsage,
             uint64_t inConsumerUsage, std::string requestorName = "<Unknown>");
 
-    // create a buffer from an existing handle
+    // Create a GraphicBuffer from an existing handle.
+    enum HandleWrapMethod : uint8_t {
+        // Wrap and use the handle directly.  It assumes the handle has been
+        // registered and never fails.  The handle must have a longer lifetime
+        // than this wrapping GraphicBuffer.
+        //
+        // This can be used when, for example, you want to wrap a handle that
+        // is already managed by another GraphicBuffer.
+        WRAP_HANDLE,
+
+        // Take ownership of the handle and use it directly.  It assumes the
+        // handle has been registered and never fails.
+        //
+        // This can be used to manage an already registered handle with
+        // GraphicBuffer.
+        TAKE_HANDLE,
+
+        // Take onwership of an unregistered handle and use it directly.  It
+        // can fail when the buffer does not register.  There is no ownership
+        // transfer on failures.
+        //
+        // This can be used to, for example, create a GraphicBuffer from a
+        // handle returned by Parcel::readNativeHandle.
+        TAKE_UNREGISTERED_HANDLE,
+
+        // Make a clone of the handle and use the cloned handle.  It can fail
+        // when cloning fails or when the buffer does not register.  There is
+        // never ownership transfer.
+        //
+        // This can be used to create a GraphicBuffer from a handle that
+        // cannot be used directly, such as one from hidl_handle.
+        CLONE_HANDLE,
+    };
+    GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method,
+            uint32_t width, uint32_t height,
+            PixelFormat format, uint32_t layerCount,
+            uint64_t producerUsage, uint64_t consumerUsage, uint32_t stride);
+
+    // These functions are deprecated because they do not distinguish producer
+    // and consumer usages.
+    GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method,
+            uint32_t width, uint32_t height,
+            PixelFormat format, uint32_t layerCount,
+            uint32_t usage, uint32_t stride)
+        : GraphicBuffer(handle, method, width, height, format, layerCount,
+                usage, usage, stride) {}
     GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
             uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride,
             native_handle_t* inHandle, bool keepOwnership);
-
-    // create a buffer from an existing handle using gralloc1
     GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
-            uint32_t inLayerCount, uint32_t inProducerUsage,
-            uint32_t inConsumerUsage, uint32_t inStride,
-            native_handle_t* inHandle, bool keepOwnership);
-
-    // create a buffer from an existing ANativeWindowBuffer
-    GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership);
+            uint32_t inUsage, std::string requestorName = "<Unknown>");
 
     // return status
     status_t initCheck() const;
@@ -114,6 +153,9 @@
         mGenerationNumber = generation;
     }
 
+    // This function is privileged.  It requires access to the allocator
+    // device or service, which usually involves adding suitable selinux
+    // rules.
     status_t reallocate(uint32_t inWidth, uint32_t inHeight,
             PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage);
 
@@ -175,19 +217,21 @@
     GraphicBuffer& operator = (const GraphicBuffer& rhs);
     const GraphicBuffer& operator = (const GraphicBuffer& rhs) const;
 
-    status_t initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
-            uint32_t inLayerCount, uint64_t inProducerUsage,
-            uint64_t inConsumerUsage, std::string requestorName);
+    status_t initWithSize(uint32_t inWidth, uint32_t inHeight,
+            PixelFormat inFormat, uint32_t inLayerCount,
+            uint64_t inProducerUsage, uint64_t inConsumerUsage,
+            std::string requestorName);
+
+    status_t initWithHandle(const native_handle_t* handle,
+            HandleWrapMethod method, uint32_t width, uint32_t height,
+            PixelFormat format, uint32_t layerCount,
+            uint64_t producerUsage, uint64_t consumerUsage, uint32_t stride);
 
     void free_handle();
 
     GraphicBufferMapper& mBufferMapper;
     ssize_t mInitCheck;
 
-    // If we're wrapping another buffer then this reference will make sure it
-    // doesn't get freed.
-    sp<ANativeWindowBuffer> mWrappedBuffer;
-
     uint64_t mId;
 
     // Stores the generation number of this buffer. If this number does not
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h
index 0e723c5..44c1352 100644
--- a/libs/binder/include/binder/SafeInterface.h
+++ b/libs/binder/include/binder/SafeInterface.h
@@ -45,6 +45,16 @@
         return callParcel("writeBool", [&]() { return parcel->writeBool(b); });
     }
     template <typename T>
+    typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type read(
+            const Parcel& parcel, T* t) const {
+        return callParcel("read(Flattenable)", [&]() { return parcel.read(*t); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type write(
+            Parcel* parcel, const T& t) const {
+        return callParcel("write(Flattenable)", [&]() { return parcel->write(t); });
+    }
+    template <typename T>
     typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type read(
             const Parcel& parcel, T* t) const {
         return callParcel("read(LightFlattenable)", [&]() { return parcel.read(*t); });
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index ac2f4d5..d1f63a7 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -65,6 +65,25 @@
     uint8_t mPadding[4] = {}; // Avoids a warning from -Wpadded
 };
 
+struct TestFlattenable : Flattenable<TestFlattenable> {
+    TestFlattenable() = default;
+    explicit TestFlattenable(int32_t v) : value(v) {}
+
+    // Flattenable protocol
+    size_t getFlattenedSize() const { return sizeof(value); }
+    size_t getFdCount() const { return 0; }
+    status_t flatten(void*& buffer, size_t& size, int*& /*fds*/, size_t& /*count*/) const {
+        FlattenableUtils::write(buffer, size, value);
+        return NO_ERROR;
+    }
+    status_t unflatten(void const*& buffer, size_t& size, int const*& /*fds*/, size_t& /*count*/) {
+        FlattenableUtils::read(buffer, size, value);
+        return NO_ERROR;
+    }
+
+    int32_t value = 0;
+};
+
 struct TestLightFlattenable : LightFlattenablePod<TestLightFlattenable> {
     TestLightFlattenable() = default;
     explicit TestLightFlattenable(int32_t v) : value(v) {}
@@ -142,6 +161,7 @@
         SetDeathToken = IBinder::FIRST_CALL_TRANSACTION,
         ReturnsNoMemory,
         LogicalNot,
+        IncrementFlattenable,
         IncrementLightFlattenable,
         IncrementNoCopyNoMove,
         ToUpper,
@@ -161,6 +181,7 @@
 
     // These are ordered according to their corresponding methods in SafeInterface::ParcelHandler
     virtual status_t logicalNot(bool a, bool* notA) const = 0;
+    virtual status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const = 0;
     virtual status_t increment(const TestLightFlattenable& a,
                                TestLightFlattenable* aPlusOne) const = 0;
     virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0;
@@ -192,6 +213,12 @@
         ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
         return callRemote<decltype(&ISafeInterfaceTest::logicalNot)>(Tag::LogicalNot, a, notA);
     }
+    status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const override {
+        using Signature =
+                status_t (ISafeInterfaceTest::*)(const TestFlattenable&, TestFlattenable*) const;
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<Signature>(Tag::IncrementFlattenable, a, aPlusOne);
+    }
     status_t increment(const TestLightFlattenable& a,
                        TestLightFlattenable* aPlusOne) const override {
         using Signature = status_t (ISafeInterfaceTest::*)(const TestLightFlattenable&,
@@ -263,6 +290,11 @@
         *notA = !a;
         return NO_ERROR;
     }
+    status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        aPlusOne->value = a.value + 1;
+        return NO_ERROR;
+    }
     status_t increment(const TestLightFlattenable& a,
                        TestLightFlattenable* aPlusOne) const override {
         ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
@@ -317,6 +349,11 @@
             case ISafeInterfaceTest::Tag::LogicalNot: {
                 return callLocal(data, reply, &ISafeInterfaceTest::logicalNot);
             }
+            case ISafeInterfaceTest::Tag::IncrementFlattenable: {
+                using Signature = status_t (ISafeInterfaceTest::*)(const TestFlattenable& a,
+                                                                   TestFlattenable* aPlusOne) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
             case ISafeInterfaceTest::Tag::IncrementLightFlattenable: {
                 using Signature =
                         status_t (ISafeInterfaceTest::*)(const TestLightFlattenable& a,
@@ -428,6 +465,14 @@
     ASSERT_EQ(!b, notB);
 }
 
+TEST_F(SafeInterfaceTest, TestIncrementFlattenable) {
+    const TestFlattenable a{1};
+    TestFlattenable aPlusOne{0};
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a.value + 1, aPlusOne.value);
+}
+
 TEST_F(SafeInterfaceTest, TestIncrementLightFlattenable) {
     const TestLightFlattenable a{1};
     TestLightFlattenable aPlusOne{0};
diff --git a/libs/binder/tests/binderValueTypeTest.cpp b/libs/binder/tests/binderValueTypeTest.cpp
index 1a05a52..c8f4697 100644
--- a/libs/binder/tests/binderValueTypeTest.cpp
+++ b/libs/binder/tests/binderValueTypeTest.cpp
@@ -106,6 +106,6 @@
     value_a.swap(value_b);
     ASSERT_FALSE(value_b.empty());
     ASSERT_TRUE(value_a.empty());
-    ASSERT_TRUE(value_a.getInt(&int_x));
+    ASSERT_TRUE(value_b.getInt(&int_x));
     ASSERT_EQ(31337, int_x);
 }
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
index 2732071..fe9e05a 100644
--- a/libs/binder/tests/schd-dbg.cpp
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -15,6 +15,7 @@
 #include <pthread.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#include <fstream>
 
 using namespace std;
 using namespace android;
@@ -41,6 +42,8 @@
 
 #define DUMP_PRICISION 3
 
+string trace_path = "/sys/kernel/debug/tracing";
+
 // the default value
 int no_process = 2;
 int iterations = 100;
@@ -48,6 +51,23 @@
 int no_inherent = 0;
 int no_sync = 0;
 int verbose = 0;
+int trace;
+
+bool traceIsOn() {
+  fstream file;
+  file.open(trace_path + "/tracing_on", ios::in);
+  char on;
+  file >> on;
+  file.close();
+  return on == '1';
+}
+
+void traceStop() {
+  ofstream file;
+  file.open(trace_path + "/tracing_on", ios::out | ios::trunc);
+  file << '0' << endl;
+  file.close();
+}
 
 // the deadline latency that we are interested in
 uint64_t deadline_us = 2500;
@@ -197,13 +217,29 @@
   uint64_t m_transactions = 0;
   uint64_t m_total_time = 0;
   uint64_t m_miss = 0;
-
+  bool tracing;
+  Results(bool _tracing) : tracing(_tracing) {
+  }
+  inline bool miss_deadline(uint64_t nano) {
+    return nano > deadline_us * 1000;
+  }
   void add_time(uint64_t nano) {
     m_best = min(nano, m_best);
     m_worst = max(nano, m_worst);
     m_transactions += 1;
     m_total_time += nano;
-    if (nano > deadline_us * 1000) m_miss++;
+    if (miss_deadline(nano)) m_miss++;
+    if (miss_deadline(nano) && tracing) {
+      // There might be multiple process pair running the test concurrently
+      // each may execute following statements and only the first one actually
+      // stop the trace and any traceStop() afterthen has no effect.
+      traceStop();
+      cout << endl;
+      cout << "deadline triggered: halt & stop trace" << endl;
+      cout << "log:" + trace_path + "/trace" << endl;
+      cout << endl;
+      exit(1);
+    }
   }
   void dump() {
     double best = (double)m_best / 1.0E6;
@@ -212,8 +248,9 @@
     // FIXME: libjson?
     cout << std::setprecision(DUMP_PRICISION) << "{ \"avg\":" << setw(5) << left
          << average << ", \"wst\":" << setw(5) << left << worst
-         << ", \"bst\":" << setw(5) << left << best << ", \"miss\":" << m_miss
-         << "}";
+         << ", \"bst\":" << setw(5) << left << best << ", \"miss\":" << setw(5)
+         << left << m_miss << ", \"meetR\":" << setw(3) << left
+         << (1.0 - (double)m_miss / m_transactions) << "}";
   }
 };
 
@@ -272,7 +309,7 @@
 void worker_fx(int num, int no_process, int iterations, int payload_size,
                Pipe p) {
   int dummy;
-  Results results_other, results_fifo;
+  Results results_other(false), results_fifo(trace);
 
   // Create BinderWorkerService and for go.
   ProcessState::self()->startThreadPool();
@@ -389,8 +426,28 @@
     }
     if (string(argv[i]) == "-v") {
       verbose = 1;
-      i++;
     }
+    // The -trace argument is used like that:
+    //
+    // First start trace with atrace command as usual
+    // >atrace --async_start sched freq
+    //
+    // then use schd-dbg with -trace arguments
+    //./schd-dbg -trace -deadline_us 2500
+    //
+    // This makes schd-dbg to stop trace once it detects a transaction
+    // duration over the deadline. By writing '0' to
+    // /sys/kernel/debug/tracing and halt the process. The tracelog is
+    // then available on /sys/kernel/debug/trace
+    if (string(argv[i]) == "-trace") {
+      trace = 1;
+    }
+  }
+  if (trace && !traceIsOn()) {
+    cout << "trace is not running" << endl;
+    cout << "check " << trace_path + "/tracing_on" << endl;
+    cout << "use atrace --async_start first" << endl;
+    exit(-1);
   }
   vector<Pipe> pipes;
   thread_dump("main");
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 5fc6abe..90ab286 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -117,6 +117,7 @@
         "android.hidl.token@1.0-utils",
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
     ],
 
     export_shared_lib_headers: [
@@ -126,7 +127,9 @@
         "android.hardware.graphics.bufferqueue@1.0",
     ],
 
-    header_libs: ["android.hardware.configstore-utils"],
+    export_include_dirs: [
+        "include",
+    ],
 }
 
 subdirs = ["tests"]
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index 51a8d67..ef7a6f5 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -17,8 +17,8 @@
 #include <private/gui/BitTube.h>
 
 #include <stdint.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 
 #include <fcntl.h>
 #include <unistd.h>
@@ -27,45 +27,21 @@
 
 #include <binder/Parcel.h>
 
-
 namespace android {
-// ----------------------------------------------------------------------------
+namespace gui {
 
-// Socket buffer size.  The default is typically about 128KB, which is much larger than
-// we really need.  So we make it smaller.
+// Socket buffer size.  The default is typically about 128KB, which is much larger than we really
+// need. So we make it smaller.
 static const size_t DEFAULT_SOCKET_BUFFER_SIZE = 4 * 1024;
 
-
-BitTube::BitTube()
-    : mSendFd(-1), mReceiveFd(-1)
-{
-    init(DEFAULT_SOCKET_BUFFER_SIZE, DEFAULT_SOCKET_BUFFER_SIZE);
-}
-
-BitTube::BitTube(size_t bufsize)
-    : mSendFd(-1), mReceiveFd(-1)
-{
+BitTube::BitTube(size_t bufsize) {
     init(bufsize, bufsize);
 }
 
-BitTube::BitTube(const Parcel& data)
-    : mSendFd(-1), mReceiveFd(-1)
-{
-    mReceiveFd = dup(data.readFileDescriptor());
-    if (mReceiveFd < 0) {
-        mReceiveFd = -errno;
-        ALOGE("BitTube(Parcel): can't dup filedescriptor (%s)",
-                strerror(-mReceiveFd));
-    }
-}
+BitTube::BitTube(DefaultSizeType) : BitTube(DEFAULT_SOCKET_BUFFER_SIZE) {}
 
-BitTube::~BitTube()
-{
-    if (mSendFd >= 0)
-        close(mSendFd);
-
-    if (mReceiveFd >= 0)
-        close(mReceiveFd);
+BitTube::BitTube(const Parcel& data) {
+    readFromParcel(&data);
 }
 
 void BitTube::init(size_t rcvbuf, size_t sndbuf) {
@@ -74,39 +50,43 @@
         size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
         setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
         setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
-        // sine we don't use the "return channel", we keep it small...
+        // since we don't use the "return channel", we keep it small...
         setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
         setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
         fcntl(sockets[0], F_SETFL, O_NONBLOCK);
         fcntl(sockets[1], F_SETFL, O_NONBLOCK);
-        mReceiveFd = sockets[0];
-        mSendFd = sockets[1];
+        mReceiveFd.reset(sockets[0]);
+        mSendFd.reset(sockets[1]);
     } else {
-        mReceiveFd = -errno;
-        ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
+        mReceiveFd.reset();
+        ALOGE("BitTube: pipe creation failed (%s)", strerror(errno));
     }
 }
 
-status_t BitTube::initCheck() const
-{
+status_t BitTube::initCheck() const {
     if (mReceiveFd < 0) {
         return status_t(mReceiveFd);
     }
     return NO_ERROR;
 }
 
-int BitTube::getFd() const
-{
+int BitTube::getFd() const {
     return mReceiveFd;
 }
 
-int BitTube::getSendFd() const
-{
+int BitTube::getSendFd() const {
     return mSendFd;
 }
 
-ssize_t BitTube::write(void const* vaddr, size_t size)
-{
+base::unique_fd BitTube::moveReceiveFd() {
+    return std::move(mReceiveFd);
+}
+
+void BitTube::setReceiveFd(base::unique_fd&& receiveFd) {
+    mReceiveFd = std::move(receiveFd);
+}
+
+ssize_t BitTube::write(void const* vaddr, size_t size) {
     ssize_t err, len;
     do {
         len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
@@ -116,62 +96,66 @@
     return err == 0 ? len : -err;
 }
 
-ssize_t BitTube::read(void* vaddr, size_t size)
-{
+ssize_t BitTube::read(void* vaddr, size_t size) {
     ssize_t err, len;
     do {
         len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
         err = len < 0 ? errno : 0;
     } while (err == EINTR);
     if (err == EAGAIN || err == EWOULDBLOCK) {
-        // EAGAIN means that we have non-blocking I/O but there was
-        // no data to be read. Nothing the client should care about.
+        // EAGAIN means that we have non-blocking I/O but there was no data to be read. Nothing the
+        // client should care about.
         return 0;
     }
     return err == 0 ? len : -err;
 }
 
-status_t BitTube::writeToParcel(Parcel* reply) const
-{
-    if (mReceiveFd < 0)
-        return -EINVAL;
+status_t BitTube::writeToParcel(Parcel* reply) const {
+    if (mReceiveFd < 0) return -EINVAL;
 
     status_t result = reply->writeDupFileDescriptor(mReceiveFd);
-    close(mReceiveFd);
-    mReceiveFd = -1;
+    mReceiveFd.reset();
     return result;
 }
 
+status_t BitTube::readFromParcel(const Parcel* parcel) {
+    mReceiveFd.reset(dup(parcel->readFileDescriptor()));
+    if (mReceiveFd < 0) {
+        mReceiveFd.reset();
+        int error = errno;
+        ALOGE("BitTube::readFromParcel: can't dup file descriptor (%s)", strerror(error));
+        return -error;
+    }
+    return NO_ERROR;
+}
 
-ssize_t BitTube::sendObjects(const sp<BitTube>& tube,
-        void const* events, size_t count, size_t objSize)
-{
+ssize_t BitTube::sendObjects(BitTube* tube, void const* events, size_t count, size_t objSize) {
     const char* vaddr = reinterpret_cast<const char*>(events);
-    ssize_t size = tube->write(vaddr, count*objSize);
+    ssize_t size = tube->write(vaddr, count * objSize);
 
     // should never happen because of SOCK_SEQPACKET
     LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
-            "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were sent!)",
-            count, objSize, size);
+                        "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were "
+                        "sent!)",
+                        count, objSize, size);
 
-    //ALOGE_IF(size<0, "error %d sending %d events", size, count);
+    // ALOGE_IF(size<0, "error %d sending %d events", size, count);
     return size < 0 ? size : size / static_cast<ssize_t>(objSize);
 }
 
-ssize_t BitTube::recvObjects(const sp<BitTube>& tube,
-        void* events, size_t count, size_t objSize)
-{
+ssize_t BitTube::recvObjects(BitTube* tube, void* events, size_t count, size_t objSize) {
     char* vaddr = reinterpret_cast<char*>(events);
-    ssize_t size = tube->read(vaddr, count*objSize);
+    ssize_t size = tube->read(vaddr, count * objSize);
 
     // should never happen because of SOCK_SEQPACKET
     LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
-            "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were received!)",
-            count, objSize, size);
+                        "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were "
+                        "received!)",
+                        count, objSize, size);
 
-    //ALOGE_IF(size<0, "error %d receiving %d events", size, count);
+    // ALOGE_IF(size<0, "error %d receiving %d events", size, count);
     return size < 0 ? size : size / static_cast<ssize_t>(objSize);
 }
 
-// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace gui
+} // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 27ced61..aef231a 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -951,7 +951,11 @@
 
     // Call back without the main BufferQueue lock held, but with the callback
     // lock held so we can ensure that callbacks occur in order
-    {
+
+    int connectedApi;
+    sp<Fence> lastQueuedFence;
+
+    { // scope for the lock
         Mutex::Autolock lock(mCallbackMutex);
         while (callbackTicket != mCurrentCallbackTicket) {
             mCallbackCondition.wait(mCallbackMutex);
@@ -963,20 +967,24 @@
             frameReplacedListener->onFrameReplaced(item);
         }
 
+        connectedApi = mCore->mConnectedApi;
+        lastQueuedFence = std::move(mLastQueueBufferFence);
+
+        mLastQueueBufferFence = std::move(acquireFence);
+        mLastQueuedCrop = item.mCrop;
+        mLastQueuedTransform = item.mTransform;
+
         ++mCurrentCallbackTicket;
         mCallbackCondition.broadcast();
     }
 
     // Wait without lock held
-    if (mCore->mConnectedApi == NATIVE_WINDOW_API_EGL) {
+    if (connectedApi == NATIVE_WINDOW_API_EGL) {
         // Waiting here allows for two full buffers to be queued but not a
         // third. In the event that frames take varying time, this makes a
         // small trade-off in favor of latency rather than throughput.
-        mLastQueueBufferFence->waitForever("Throttling EGL Production");
+        lastQueuedFence->waitForever("Throttling EGL Production");
     }
-    mLastQueueBufferFence = std::move(acquireFence);
-    mLastQueuedCrop = item.mCrop;
-    mLastQueuedTransform = item.mTransform;
 
     // Update and get FrameEventHistory.
     nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 07e07e0..1507d51 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -37,7 +37,8 @@
     if (sf != NULL) {
         mEventConnection = sf->createDisplayEventConnection();
         if (mEventConnection != NULL) {
-            mDataChannel = mEventConnection->getDataChannel();
+            mDataChannel = std::make_unique<gui::BitTube>();
+            mEventConnection->stealReceiveChannel(mDataChannel.get());
         }
     }
 }
@@ -80,19 +81,19 @@
 
 ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
         size_t count) {
-    return DisplayEventReceiver::getEvents(mDataChannel, events, count);
+    return DisplayEventReceiver::getEvents(mDataChannel.get(), events, count);
 }
 
-ssize_t DisplayEventReceiver::getEvents(const sp<BitTube>& dataChannel,
+ssize_t DisplayEventReceiver::getEvents(gui::BitTube* dataChannel,
         Event* events, size_t count)
 {
-    return BitTube::recvObjects(dataChannel, events, count);
+    return gui::BitTube::recvObjects(dataChannel, events, count);
 }
 
-ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,
+ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,
         Event const* events, size_t count)
 {
-    return BitTube::sendObjects(dataChannel, events, count);
+    return gui::BitTube::sendObjects(dataChannel, events, count);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 8cadc4d..85ac304 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -14,98 +14,86 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
 #include <gui/IConsumerListener.h>
+
 #include <gui/BufferItem.h>
 
-// ---------------------------------------------------------------------------
 namespace android {
-// ---------------------------------------------------------------------------
 
-enum {
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
     ON_DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
     ON_FRAME_AVAILABLE,
-    ON_BUFFER_RELEASED,
+    ON_FRAME_REPLACED,
+    ON_BUFFERS_RELEASED,
     ON_SIDEBAND_STREAM_CHANGED,
-    GET_FRAME_TIMESTAMPS
+    LAST = ON_SIDEBAND_STREAM_CHANGED,
 };
 
-class BpConsumerListener : public BpInterface<IConsumerListener>
-{
+} // Anonymous namespace
+
+class BpConsumerListener : public SafeBpInterface<IConsumerListener> {
 public:
     explicit BpConsumerListener(const sp<IBinder>& impl)
-        : BpInterface<IConsumerListener>(impl) {
+          : SafeBpInterface<IConsumerListener>(impl, "BpConsumerListener") {}
+
+    ~BpConsumerListener() override;
+
+    void onDisconnect() override {
+        callRemoteAsync<decltype(&IConsumerListener::onDisconnect)>(Tag::ON_DISCONNECT);
     }
 
-    virtual ~BpConsumerListener();
-
-    virtual void onDisconnect() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
-        remote()->transact(ON_DISCONNECT, data, &reply, IBinder::FLAG_ONEWAY);
+    void onFrameAvailable(const BufferItem& item) override {
+        callRemoteAsync<decltype(&IConsumerListener::onFrameAvailable)>(Tag::ON_FRAME_AVAILABLE,
+                                                                        item);
     }
 
-    virtual void onFrameAvailable(const BufferItem& item) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
-        data.write(item);
-        remote()->transact(ON_FRAME_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY);
+    void onFrameReplaced(const BufferItem& item) override {
+        callRemoteAsync<decltype(&IConsumerListener::onFrameReplaced)>(Tag::ON_FRAME_REPLACED,
+                                                                       item);
     }
 
-    virtual void onBuffersReleased() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
-        remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
+    void onBuffersReleased() override {
+        callRemoteAsync<decltype(&IConsumerListener::onBuffersReleased)>(Tag::ON_BUFFERS_RELEASED);
     }
 
-    virtual void onSidebandStreamChanged() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
-        remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+    void onSidebandStreamChanged() override {
+        callRemoteAsync<decltype(&IConsumerListener::onSidebandStreamChanged)>(
+                Tag::ON_SIDEBAND_STREAM_CHANGED);
+    }
+
+    void addAndGetFrameTimestamps(const NewFrameEventsEntry* /*newTimestamps*/,
+                                  FrameEventHistoryDelta* /*outDelta*/) override {
+        LOG_ALWAYS_FATAL("IConsumerListener::addAndGetFrameTimestamps cannot be proxied");
     }
 };
 
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpConsumerListener::~BpConsumerListener() {}
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpConsumerListener::~BpConsumerListener() = default;
+ConsumerListener::~ConsumerListener() = default;
 
 IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener");
 
-// ----------------------------------------------------------------------
-
-status_t BnConsumerListener::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-        case ON_DISCONNECT: {
-            CHECK_INTERFACE(IConsumerListener, data, reply);
-            onDisconnect();
-            return NO_ERROR; }
-        case ON_FRAME_AVAILABLE: {
-            CHECK_INTERFACE(IConsumerListener, data, reply);
-            BufferItem item;
-            data.read(item);
-            onFrameAvailable(item);
-            return NO_ERROR; }
-        case ON_BUFFER_RELEASED: {
-            CHECK_INTERFACE(IConsumerListener, data, reply);
-            onBuffersReleased();
-            return NO_ERROR; }
-        case ON_SIDEBAND_STREAM_CHANGED: {
-            CHECK_INTERFACE(IConsumerListener, data, reply);
-            onSidebandStreamChanged();
-            return NO_ERROR; }
+status_t BnConsumerListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                        uint32_t flags) {
+    if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+        return BBinder::onTransact(code, data, reply, flags);
     }
-    return BBinder::onTransact(code, data, reply, flags);
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::ON_DISCONNECT:
+            return callLocalAsync(data, reply, &IConsumerListener::onDisconnect);
+        case Tag::ON_FRAME_AVAILABLE:
+            return callLocalAsync(data, reply, &IConsumerListener::onFrameAvailable);
+        case Tag::ON_FRAME_REPLACED:
+            return callLocalAsync(data, reply, &IConsumerListener::onFrameReplaced);
+        case Tag::ON_BUFFERS_RELEASED:
+            return callLocalAsync(data, reply, &IConsumerListener::onBuffersReleased);
+        case Tag::ON_SIDEBAND_STREAM_CHANGED:
+            return callLocalAsync(data, reply, &IConsumerListener::onSidebandStreamChanged);
+    }
 }
 
-ConsumerListener::~ConsumerListener() = default;
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
+} // namespace android
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index e5c3c48..c0e246f 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -14,89 +14,67 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-#include <binder/Parcel.h>
-
 #include <gui/IDisplayEventConnection.h>
 
 #include <private/gui/BitTube.h>
 
 namespace android {
-// ----------------------------------------------------------------------------
 
-enum {
-    GET_DATA_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+    STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
     SET_VSYNC_RATE,
-    REQUEST_NEXT_VSYNC
+    REQUEST_NEXT_VSYNC,
+    LAST = REQUEST_NEXT_VSYNC,
 };
 
-class BpDisplayEventConnection : public BpInterface<IDisplayEventConnection>
-{
+} // Anonymous namespace
+
+class BpDisplayEventConnection : public SafeBpInterface<IDisplayEventConnection> {
 public:
     explicit BpDisplayEventConnection(const sp<IBinder>& impl)
-        : BpInterface<IDisplayEventConnection>(impl)
-    {
+          : SafeBpInterface<IDisplayEventConnection>(impl, "BpDisplayEventConnection") {}
+
+    ~BpDisplayEventConnection() override;
+
+    status_t stealReceiveChannel(gui::BitTube* outChannel) override {
+        return callRemote<decltype(
+                &IDisplayEventConnection::stealReceiveChannel)>(Tag::STEAL_RECEIVE_CHANNEL,
+                                                                outChannel);
     }
 
-    virtual ~BpDisplayEventConnection();
-
-    virtual sp<BitTube> getDataChannel() const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
-        remote()->transact(GET_DATA_CHANNEL, data, &reply);
-        return new BitTube(reply);
+    status_t setVsyncRate(uint32_t count) override {
+        return callRemote<decltype(&IDisplayEventConnection::setVsyncRate)>(Tag::SET_VSYNC_RATE,
+                                                                            count);
     }
 
-    virtual void setVsyncRate(uint32_t count) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
-        data.writeUint32(count);
-        remote()->transact(SET_VSYNC_RATE, data, &reply);
-    }
-
-    virtual void requestNextVsync() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
-        remote()->transact(REQUEST_NEXT_VSYNC, data, &reply, IBinder::FLAG_ONEWAY);
+    void requestNextVsync() override {
+        callRemoteAsync<decltype(&IDisplayEventConnection::requestNextVsync)>(
+                Tag::REQUEST_NEXT_VSYNC);
     }
 };
 
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpDisplayEventConnection::~BpDisplayEventConnection() {}
+// Out-of-line virtual method definition to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpDisplayEventConnection::~BpDisplayEventConnection() = default;
 
 IMPLEMENT_META_INTERFACE(DisplayEventConnection, "android.gui.DisplayEventConnection");
 
-// ----------------------------------------------------------------------------
-
-status_t BnDisplayEventConnection::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-        case GET_DATA_CHANNEL: {
-            CHECK_INTERFACE(IDisplayEventConnection, data, reply);
-            sp<BitTube> channel(getDataChannel());
-            channel->writeToParcel(reply);
-            return NO_ERROR;
-        }
-        case SET_VSYNC_RATE: {
-            CHECK_INTERFACE(IDisplayEventConnection, data, reply);
-            setVsyncRate(data.readUint32());
-            return NO_ERROR;
-        }
-        case REQUEST_NEXT_VSYNC: {
-            CHECK_INTERFACE(IDisplayEventConnection, data, reply);
-            requestNextVsync();
-            return NO_ERROR;
-        }
+status_t BnDisplayEventConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                              uint32_t flags) {
+    if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+        return BBinder::onTransact(code, data, reply, flags);
     }
-    return BBinder::onTransact(code, data, reply, flags);
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::STEAL_RECEIVE_CHANNEL:
+            return callLocal(data, reply, &IDisplayEventConnection::stealReceiveChannel);
+        case Tag::SET_VSYNC_RATE:
+            return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate);
+        case Tag::REQUEST_NEXT_VSYNC:
+            return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync);
+    }
 }
 
-// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 2d2146b..679f44b 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -17,24 +17,28 @@
 // tag as surfaceflinger
 #define LOG_TAG "SurfaceFlinger"
 
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/types.h>
+#include <gui/ISurfaceComposerClient.h>
 
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/Parcel.h>
+#include <gui/IGraphicBufferProducer.h>
+
 #include <binder/SafeInterface.h>
 
 #include <ui/FrameStats.h>
-#include <ui/Point.h>
-#include <ui/Rect.h>
-
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/ISurfaceComposerClient.h>
 
 namespace android {
 
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+    CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
+    DESTROY_SURFACE,
+    CLEAR_LAYER_FRAME_STATS,
+    GET_LAYER_FRAME_STATS,
+    LAST = GET_LAYER_FRAME_STATS,
+};
+
+} // Anonymous namespace
+
 class BpSurfaceComposerClient : public SafeBpInterface<ISurfaceComposerClient> {
 public:
     explicit BpSurfaceComposerClient(const sp<IBinder>& impl)
@@ -46,7 +50,7 @@
                            uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
                            uint32_t ownerUid, sp<IBinder>* handle,
                            sp<IGraphicBufferProducer>* gbp) override {
-        return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CreateSurface,
+        return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,
                                                                             name, width, height,
                                                                             format, flags, parent,
                                                                             windowType, ownerUid,
@@ -54,18 +58,19 @@
     }
 
     status_t destroySurface(const sp<IBinder>& handle) override {
-        return callRemote<decltype(&ISurfaceComposerClient::destroySurface)>(Tag::DestroySurface,
+        return callRemote<decltype(&ISurfaceComposerClient::destroySurface)>(Tag::DESTROY_SURFACE,
                                                                              handle);
     }
 
     status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
         return callRemote<decltype(
-                &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::ClearLayerFrameStats, handle);
+                &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::CLEAR_LAYER_FRAME_STATS,
+                                                                handle);
     }
 
     status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const override {
         return callRemote<decltype(
-                &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GetLayerFrameStats, handle,
+                &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GET_LAYER_FRAME_STATS, handle,
                                                               outStats);
     }
 };
@@ -80,26 +85,19 @@
 
 status_t BnSurfaceComposerClient::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                              uint32_t flags) {
-    if (code < IBinder::FIRST_CALL_TRANSACTION || code >= static_cast<uint32_t>(Tag::Last)) {
+    if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
         return BBinder::onTransact(code, data, reply, flags);
     }
     auto tag = static_cast<Tag>(code);
     switch (tag) {
-        case Tag::CreateSurface: {
+        case Tag::CREATE_SURFACE:
             return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
-        }
-        case Tag::DestroySurface: {
+        case Tag::DESTROY_SURFACE:
             return callLocal(data, reply, &ISurfaceComposerClient::destroySurface);
-        }
-        case Tag::ClearLayerFrameStats: {
+        case Tag::CLEAR_LAYER_FRAME_STATS:
             return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
-        }
-        case Tag::GetLayerFrameStats: {
+        case Tag::GET_LAYER_FRAME_STATS:
             return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats);
-        }
-        case Tag::Last:
-            // Should not be possible because of the check at the beginning of the method
-            return BBinder::onTransact(code, data, reply, flags);
     }
 }
 
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 06fc31d..1149b89 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -505,7 +505,11 @@
          mFrameEventHistory->applyDelta(frameTimestamps);
     }
 
-    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
+    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
+        if (mReportRemovedBuffers && (gbuf != nullptr)) {
+            mRemovedBuffers.clear();
+            mRemovedBuffers.push_back(gbuf);
+        }
         result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
         if (result != NO_ERROR) {
             ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
@@ -1075,10 +1079,16 @@
 }
 
 int Surface::connect(int api, const sp<IProducerListener>& listener) {
+    return connect(api, listener, false);
+}
+
+int Surface::connect(
+        int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
     ATRACE_CALL();
     ALOGV("Surface::connect");
     Mutex::Autolock lock(mMutex);
     IGraphicBufferProducer::QueueBufferOutput output;
+    mReportRemovedBuffers = reportBufferRemoval;
     int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
     if (err == NO_ERROR) {
         mDefaultWidth = output.width;
@@ -1109,6 +1119,7 @@
     ATRACE_CALL();
     ALOGV("Surface::disconnect");
     Mutex::Autolock lock(mMutex);
+    mRemovedBuffers.clear();
     mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;
     mSharedBufferHasBeenQueued = false;
     freeAllBuffers();
@@ -1156,9 +1167,16 @@
         *outFence = Fence::NO_FENCE;
     }
 
+    if (mReportRemovedBuffers) {
+        mRemovedBuffers.clear();
+    }
+
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         if (mSlots[i].buffer != NULL &&
                 mSlots[i].buffer->handle == buffer->handle) {
+            if (mReportRemovedBuffers) {
+                mRemovedBuffers.push_back(mSlots[i].buffer);
+            }
             mSlots[i].buffer = NULL;
         }
     }
@@ -1184,6 +1202,10 @@
         graphicBuffer->mGenerationNumber = priorGeneration;
         return result;
     }
+    if (mReportRemovedBuffers && (mSlots[attachedSlot].buffer != nullptr)) {
+        mRemovedBuffers.clear();
+        mRemovedBuffers.push_back(mSlots[attachedSlot].buffer);
+    }
     mSlots[attachedSlot].buffer = graphicBuffer;
 
     return NO_ERROR;
@@ -1617,4 +1639,16 @@
     return mGraphicBufferProducer->getUniqueId(outId);
 }
 
+status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) {
+    if (out == nullptr) {
+        ALOGE("%s: out must not be null!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    *out = mRemovedBuffers;
+    mRemovedBuffers.clear();
+    return OK;
+}
+
 }; // namespace android
diff --git a/libs/gui/include/private/gui/BitTube.h b/libs/gui/include/private/gui/BitTube.h
new file mode 100644
index 0000000..13c0162
--- /dev/null
+++ b/libs/gui/include/private/gui/BitTube.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcelable.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class Parcel;
+
+namespace gui {
+
+class BitTube : public Parcelable {
+public:
+    // creates an uninitialized BitTube (to unparcel into)
+    BitTube() = default;
+
+    // creates a BitTube with a a specified send and receive buffer size
+    explicit BitTube(size_t bufsize);
+
+    // creates a BitTube with a default (4KB) send buffer
+    struct DefaultSizeType {};
+    static constexpr DefaultSizeType DefaultSize{};
+    explicit BitTube(DefaultSizeType);
+
+    explicit BitTube(const Parcel& data);
+
+    virtual ~BitTube() = default;
+
+    // check state after construction
+    status_t initCheck() const;
+
+    // get receive file-descriptor
+    int getFd() const;
+
+    // get the send file-descriptor.
+    int getSendFd() const;
+
+    // moves the receive file descriptor out of this BitTube
+    base::unique_fd moveReceiveFd();
+
+    // resets this BitTube's receive file descriptor to receiveFd
+    void setReceiveFd(base::unique_fd&& receiveFd);
+
+    // send objects (sized blobs). All objects are guaranteed to be written or the call fails.
+    template <typename T>
+    static ssize_t sendObjects(BitTube* tube, T const* events, size_t count) {
+        return sendObjects(tube, events, count, sizeof(T));
+    }
+
+    // receive objects (sized blobs). If the receiving buffer isn't large enough, excess messages
+    // are silently discarded.
+    template <typename T>
+    static ssize_t recvObjects(BitTube* tube, T* events, size_t count) {
+        return recvObjects(tube, events, count, sizeof(T));
+    }
+
+    // implement the Parcelable protocol. Only parcels the receive file descriptor
+    status_t writeToParcel(Parcel* reply) const;
+    status_t readFromParcel(const Parcel* parcel);
+
+private:
+    void init(size_t rcvbuf, size_t sndbuf);
+
+    // send a message. The write is guaranteed to send the whole message or fail.
+    ssize_t write(void const* vaddr, size_t size);
+
+    // receive a message. the passed buffer must be at least as large as the write call used to send
+    // the message, excess data is silently discarded.
+    ssize_t read(void* vaddr, size_t size);
+
+    base::unique_fd mSendFd;
+    mutable base::unique_fd mReceiveFd;
+
+    static ssize_t sendObjects(BitTube* tube, void const* events, size_t count, size_t objSize);
+
+    static ssize_t recvObjects(BitTube* tube, void* events, size_t count, size_t objSize);
+};
+
+} // namespace gui
+} // namespace android
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 3a99147..192bfc8 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -27,6 +27,8 @@
     ],
 
     shared_libs: [
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
         "liblog",
         "libEGL",
         "libGLESv1_CM",
@@ -34,6 +36,8 @@
         "libbinder",
         "libcutils",
         "libgui",
+        "libhidlbase",
+        "libhidltransport",
         "libui",
         "libutils",
         "libnativewindow"
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 9c2e838..5848c74 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -490,7 +490,7 @@
 
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     *stride = buf->getStride();
     uint8_t* img = NULL;
diff --git a/libs/gui/tests/FillBuffer.cpp b/libs/gui/tests/FillBuffer.cpp
index 079962c..ccd674f 100644
--- a/libs/gui/tests/FillBuffer.cpp
+++ b/libs/gui/tests/FillBuffer.cpp
@@ -95,7 +95,7 @@
             &anb));
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     uint8_t* img = NULL;
     ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp
index 0606839..0134273 100644
--- a/libs/gui/tests/SurfaceTextureFBO_test.cpp
+++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp
@@ -41,7 +41,7 @@
             &anb));
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with green
     uint8_t* img = NULL;
@@ -65,7 +65,7 @@
                 &anb));
         ASSERT_TRUE(anb != NULL);
 
-        buf = new GraphicBuffer(anb, false);
+        buf = GraphicBuffer::from(anb);
 
         // Fill the buffer with red
         ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index 308bd7d..c6745d0 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -42,7 +42,7 @@
             &anb));
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with the a checkerboard pattern
     uint8_t* img = NULL;
@@ -92,7 +92,7 @@
             &anb));
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with the a checkerboard pattern
     uint8_t* img = NULL;
@@ -157,7 +157,7 @@
                 &anb));
         ASSERT_TRUE(anb != NULL);
 
-        sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+        sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
         uint8_t* img = NULL;
         buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
@@ -238,7 +238,7 @@
                     return false;
                 }
 
-                sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+                sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
                 const int yuvTexOffsetY = 0;
                 int stride = buf->getStride();
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 3932b92..ce11486 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -18,7 +18,9 @@
 
 #include <gtest/gtest.h>
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <binder/ProcessState.h>
+#include <configstore/Utils.h>
 #include <cutils/properties.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/IDisplayEventConnection.h>
@@ -35,6 +37,12 @@
 namespace android {
 
 using namespace std::chrono_literals;
+// retrieve wide-color and hdr settings from configstore
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
+static bool hasWideColorDisplay =
+        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
 class FakeSurfaceComposer;
 class FakeProducerFrameEventHistory;
@@ -271,17 +279,19 @@
     bool supported;
     surface->getWideColorSupport(&supported);
 
-    // TODO(courtneygo): How can we know what device we are on to
-    // verify that this is correct?
-    char product[PROPERTY_VALUE_MAX] = "0";
-    property_get("ro.build.product", product, "0");
-    std::cerr << "[          ] product = " << product << std::endl;
-
-    if (strcmp("marlin", product) == 0 || strcmp("sailfish", product) == 0) {
-        ASSERT_EQ(true, supported);
-    } else {
-        ASSERT_EQ(false, supported);
-    }
+    // NOTE: This test assumes that device that supports
+    // wide-color (as indicated by BoardConfig) must also
+    // have a wide-color primary display.
+    // That assumption allows this test to cover devices
+    // that advertised a wide-color color mode without
+    // actually supporting wide-color to pass this test
+    // as well as the case of a device that does support
+    // wide-color (via BoardConfig) and has a wide-color
+    // primary display.
+    // NOT covered at this time is a device that supports
+    // wide color in the BoardConfig but does not support
+    // a wide-color color mode on the primary display.
+    ASSERT_EQ(hasWideColorDisplay, supported);
 }
 
 TEST_F(SurfaceTest, DynamicSetBufferCount) {
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index c0c4ac0..6c67cf8 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -25,6 +25,8 @@
 
 #include <private/android/AHardwareBufferHelpers.h>
 
+#include <ui/GraphicBuffer.h>
+
 using namespace android;
 
 static int32_t query(ANativeWindow* window, int what) {
@@ -105,6 +107,10 @@
  * vndk-stable
  **************************************************************************************************/
 
+AHardwareBuffer* ANativeWindowBuffer_getHardwareBuffer(ANativeWindowBuffer* anwb) {
+    return AHardwareBuffer_from_GraphicBuffer(static_cast<GraphicBuffer*>(anwb));
+}
+
 int ANativeWindow_OemStorageSet(ANativeWindow* window, uint32_t slot, intptr_t value) {
     if (slot < 4) {
         window->oem[slot] = value;
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
index 310e1e5..067046b 100644
--- a/libs/nativewindow/include/vndk/window.h
+++ b/libs/nativewindow/include/vndk/window.h
@@ -99,8 +99,12 @@
 
 typedef struct ANativeWindowBuffer ANativeWindowBuffer;
 
-/*****************************************************************************/
+/*
+ * Convert this ANativeWindowBuffer into a AHardwareBuffer
+ */
+AHardwareBuffer* ANativeWindowBuffer_getHardwareBuffer(ANativeWindowBuffer* anwb);
 
+/*****************************************************************************/
 
 /*
  * Stores a value into one of the 4 available slots
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index f41f187..74186df 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -40,6 +40,7 @@
     ENABLE_DATA_INJECTION,
     GET_DYNAMIC_SENSOR_LIST,
     CREATE_SENSOR_DIRECT_CONNECTION,
+    SET_OPERATION_PARAMETER,
 };
 
 class BpSensorServer : public BpInterface<ISensorServer>
@@ -117,6 +118,23 @@
         remote()->transact(CREATE_SENSOR_DIRECT_CONNECTION, data, &reply);
         return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
     }
+
+    virtual int setOperationParameter(
+            int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+        data.writeInt32(type);
+        data.writeUint32(static_cast<uint32_t>(floats.size()));
+        for (auto i : floats) {
+            data.writeFloat(i);
+        }
+        data.writeUint32(static_cast<uint32_t>(ints.size()));
+        for (auto i : ints) {
+            data.writeInt32(i);
+        }
+        remote()->transact(SET_OPERATION_PARAMETER, data, &reply);
+        return reply.readInt32();
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -183,6 +201,26 @@
             reply->writeStrongBinder(IInterface::asBinder(ch));
             return NO_ERROR;
         }
+        case SET_OPERATION_PARAMETER: {
+            CHECK_INTERFACE(ISensorServer, data, reply);
+            int32_t type;
+            Vector<float> floats;
+            Vector<int32_t> ints;
+
+            type = data.readInt32();
+            floats.resize(data.readUint32());
+            for (auto &i : floats) {
+                i = data.readFloat();
+            }
+            ints.resize(data.readUint32());
+            for (auto &i : ints) {
+                i = data.readInt32();
+            }
+
+            int32_t ret = setOperationParameter(type, floats, ints);
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index d6d3304..3fbc5eb 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -304,5 +304,14 @@
     return ret;
 }
 
+int SensorManager::setOperationParameter(
+        int type, const Vector<float> &floats, const Vector<int32_t> &ints) {
+    Mutex::Autolock _l(mLock);
+    if (assertStateLocked() != NO_ERROR) {
+        return NO_INIT;
+    }
+    return mSensorServer->setOperationParameter(type, floats, ints);
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h
index f922307..8d50062 100644
--- a/libs/sensor/include/sensor/ISensorServer.h
+++ b/libs/sensor/include/sensor/ISensorServer.h
@@ -50,6 +50,9 @@
 
     virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
             uint32_t size, int32_t type, int32_t format, const native_handle_t *resource) = 0;
+
+    virtual int setOperationParameter(
+            int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/sensor/include/sensor/SensorEventQueue.h b/libs/sensor/include/sensor/SensorEventQueue.h
index a03c7ee..baed2ee 100644
--- a/libs/sensor/include/sensor/SensorEventQueue.h
+++ b/libs/sensor/include/sensor/SensorEventQueue.h
@@ -83,7 +83,7 @@
     status_t disableSensor(Sensor const* sensor) const;
     status_t setEventRate(Sensor const* sensor, nsecs_t ns) const;
 
-    // these are here only to support SensorManager.java
+    // these are here only to support SensorManager.java and HIDL Frameworks SensorManager.
     status_t enableSensor(int32_t handle, int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs,
                           int reservedFlags) const;
     status_t disableSensor(int32_t handle) const;
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 92c9823..5fc85d3 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -64,6 +64,7 @@
     int createDirectChannel(size_t size, int channelType, const native_handle_t *channelData);
     void destroyDirectChannel(int channelNativeHandle);
     int configureDirectChannel(int channelNativeHandle, int sensorHandle, int rateLevel);
+    int setOperationParameter(int type, const Vector<float> &floats, const Vector<int32_t> &ints);
 
 private:
     // DeathRecipient interface
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 80fb064..310d25e 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -45,6 +45,7 @@
 
     srcs: [
         "ColorSpace.cpp",
+        "DebugUtils.cpp",
         "Fence.cpp",
         "FenceTime.cpp",
         "FrameStats.cpp",
@@ -66,6 +67,9 @@
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.configstore@1.0",
+	"android.hardware.configstore-utils",
+        "libbase",
         "libnativeloader",
         "libcutils",
         "libhardware",
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
new file mode 100644
index 0000000..882bd7c
--- /dev/null
+++ b/libs/ui/DebugUtils.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/DebugUtils.h>
+
+#include <android-base/stringprintf.h>
+#include <string>
+
+std::string decodeStandard(android_dataspace dataspace) {
+    const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
+    switch (dataspaceSelect) {
+        case HAL_DATASPACE_STANDARD_BT709:
+            return std::string("BT709");
+
+        case HAL_DATASPACE_STANDARD_BT601_625:
+            return std::string("BT601_625");
+
+        case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+            return std::string("BT601_625_UNADJUSTED");
+
+        case HAL_DATASPACE_STANDARD_BT601_525:
+            return std::string("BT601_525");
+
+        case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+            return std::string("BT601_525_UNADJUSTED");
+
+        case HAL_DATASPACE_STANDARD_BT2020:
+            return std::string("BT2020");
+
+        case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+            return std::string("BT2020 (constant luminance)");
+
+        case HAL_DATASPACE_STANDARD_BT470M:
+            return std::string("BT470M");
+
+        case HAL_DATASPACE_STANDARD_FILM:
+            return std::string("FILM");
+
+        case HAL_DATASPACE_STANDARD_DCI_P3:
+            return std::string("DCI-P3");
+
+        case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+            return std::string("AdobeRGB");
+
+        case 0:
+            switch (dataspace & 0xffff) {
+                case HAL_DATASPACE_JFIF:
+                    return std::string("(deprecated) JFIF (BT601_625, SMPTE_170M Full range)");
+
+                case HAL_DATASPACE_BT601_625:
+                    return std::string("(deprecated) BT601_625 (BT601_625, SMPTE_170M Limited "
+                                       "range)");
+
+                case HAL_DATASPACE_BT601_525:
+                    return std::string("(deprecated) BT601_525 (BT601_525, SMPTE_170M Limited "
+                                       "range)");
+
+                case HAL_DATASPACE_SRGB_LINEAR:
+                    return std::string("(deprecated) SRGB Linear Full range");
+
+                case HAL_DATASPACE_SRGB:
+                    return std::string("(deprecated) sRGB");
+
+                case HAL_DATASPACE_V0_BT709:
+                    return std::string("(deprecated) BT709 (BT709, SMPTE_170M Limited range)");
+
+                case HAL_DATASPACE_ARBITRARY:
+                    return std::string("ARBITRARY");
+
+                case HAL_DATASPACE_UNKNOWN:
+                // Fallthrough
+                default:
+                    return android::base::StringPrintf("Unknown deprecated dataspace code %d",
+                                                       dataspaceSelect);
+            }
+    }
+
+    return android::base::StringPrintf("Unknown dataspace code %d", dataspaceSelect);
+}
+
+std::string decodeTransfer(android_dataspace dataspace) {
+    const uint32_t dataspaceTransfer = (dataspace & HAL_DATASPACE_TRANSFER_MASK);
+    switch (dataspaceTransfer) {
+        case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
+            return std::string("Unspecified");
+
+        case HAL_DATASPACE_TRANSFER_LINEAR:
+            return std::string("Linear");
+
+        case HAL_DATASPACE_TRANSFER_SRGB:
+            return std::string("sRGB");
+
+        case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+            return std::string("SMPTE_170M");
+
+        case HAL_DATASPACE_TRANSFER_GAMMA2_2:
+            return std::string("gamma 2.2");
+
+        case HAL_DATASPACE_TRANSFER_GAMMA2_6:
+            return std::string("gamma 2.6");
+
+        case HAL_DATASPACE_TRANSFER_GAMMA2_8:
+            return std::string("gamma 2.8");
+
+        case HAL_DATASPACE_TRANSFER_ST2084:
+            return std::string("SMPTE 2084");
+
+        case HAL_DATASPACE_TRANSFER_HLG:
+            return std::string("STD-B67");
+    }
+
+    return android::base::StringPrintf("Unknown dataspace transfer %d", dataspaceTransfer);
+}
+
+std::string decodeRange(android_dataspace dataspace) {
+    const uint32_t dataspaceRange = (dataspace & HAL_DATASPACE_RANGE_MASK);
+    switch (dataspaceRange) {
+        case HAL_DATASPACE_RANGE_UNSPECIFIED:
+            return std::string("Range Unspecified");
+
+        case HAL_DATASPACE_RANGE_FULL:
+            return std::string("Full range");
+
+        case HAL_DATASPACE_RANGE_LIMITED:
+            return std::string("Limited range");
+
+        case HAL_DATASPACE_RANGE_EXTENDED:
+            return std::string("Extended range");
+    }
+
+    return android::base::StringPrintf("Unknown dataspace range %d", dataspaceRange);
+}
+
+std::string dataspaceDetails(android_dataspace dataspace) {
+    return android::base::StringPrintf("%s %s %s", decodeStandard(dataspace).c_str(),
+                                       decodeTransfer(dataspace).c_str(),
+                                       decodeRange(dataspace).c_str());
+}
+
+std::string decodeColorMode(android_color_mode colorMode) {
+    switch (colorMode) {
+        case HAL_COLOR_MODE_NATIVE:
+            return std::string("HAL_COLOR_MODE_NATIVE");
+
+        case HAL_COLOR_MODE_STANDARD_BT601_625:
+            return std::string("HAL_COLOR_MODE_BT601_625");
+
+        case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED:
+            return std::string("HAL_COLOR_MODE_BT601_625_UNADJUSTED");
+
+        case HAL_COLOR_MODE_STANDARD_BT601_525:
+            return std::string("HAL_COLOR_MODE_BT601_525");
+
+        case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED:
+            return std::string("HAL_COLOR_MODE_BT601_525_UNADJUSTED");
+
+        case HAL_COLOR_MODE_STANDARD_BT709:
+            return std::string("HAL_COLOR_MODE_BT709");
+
+        case HAL_COLOR_MODE_DCI_P3:
+            return std::string("HAL_COLOR_MODE_DCI_P3");
+
+        case HAL_COLOR_MODE_SRGB:
+            return std::string("HAL_COLOR_MODE_SRGB");
+
+        case HAL_COLOR_MODE_ADOBE_RGB:
+            return std::string("HAL_COLOR_MODE_ADOBE_RGB");
+
+        case HAL_COLOR_MODE_DISPLAY_P3:
+            return std::string("HAL_COLOR_MODE_DISPLAY_P3");
+    }
+
+    return android::base::StringPrintf("Unknown color mode %d", colorMode);
+}
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 6e84730..d21758d 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -39,6 +39,10 @@
     return id;
 }
 
+sp<GraphicBuffer> GraphicBuffer::from(ANativeWindowBuffer* anwb) {
+    return static_cast<GraphicBuffer *>(anwb);
+}
+
 GraphicBuffer::GraphicBuffer()
     : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
@@ -52,86 +56,42 @@
     handle = NULL;
 }
 
+// deprecated
 GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
         PixelFormat inFormat, uint32_t inUsage, std::string requestorName)
-    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
+    : GraphicBuffer(inWidth, inHeight, inFormat, 1, inUsage, inUsage,
+            requestorName)
 {
-    width  =
-    height =
-    stride =
-    format =
-    usage  = 0;
-    layerCount = 0;
-    handle = NULL;
-    mInitCheck = initSize(inWidth, inHeight, inFormat, 1, inUsage, inUsage,
-            std::move(requestorName));
 }
 
 GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
         PixelFormat inFormat, uint32_t inLayerCount, uint64_t producerUsage,
         uint64_t consumerUsage, std::string requestorName)
-    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
+    : GraphicBuffer()
 {
-    width  =
-    height =
-    stride =
-    format =
-    usage  = 0;
-    layerCount = 0;
-    handle = NULL;
-    mInitCheck = initSize(inWidth, inHeight, inFormat, inLayerCount,
+    mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
             producerUsage, consumerUsage, std::move(requestorName));
 }
 
+// deprecated
 GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
         PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
         uint32_t inStride, native_handle_t* inHandle, bool keepOwnership)
-    : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
-      mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
+    : GraphicBuffer(inHandle, keepOwnership ? TAKE_HANDLE : WRAP_HANDLE,
+            inWidth, inHeight, inFormat, inLayerCount, inUsage, inUsage,
+            inStride)
 {
-    width  = static_cast<int>(inWidth);
-    height = static_cast<int>(inHeight);
-    stride = static_cast<int>(inStride);
-    format = inFormat;
-    layerCount = inLayerCount;
-    usage  = static_cast<int>(inUsage);
-    handle = inHandle;
 }
 
-GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
-        PixelFormat inFormat, uint32_t inLayerCount, uint32_t inProducerUsage,
-        uint32_t inConsumerUsage, uint32_t inStride,
-        native_handle_t* inHandle, bool keepOwnership)
-    : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
-      mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
+GraphicBuffer::GraphicBuffer(const native_handle_t* handle,
+        HandleWrapMethod method, uint32_t width, uint32_t height,
+        PixelFormat format, uint32_t layerCount,
+        uint64_t producerUsage, uint64_t consumerUsage,
+        uint32_t stride)
+    : GraphicBuffer()
 {
-    width  = static_cast<int>(inWidth);
-    height = static_cast<int>(inHeight);
-    stride = static_cast<int>(inStride);
-    format = inFormat;
-    layerCount = inLayerCount;
-    usage = android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage);
-    handle = inHandle;
-}
-
-
-GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership)
-    : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
-      mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR), mWrappedBuffer(buffer), mId(getUniqueId()),
-      mGenerationNumber(0)
-{
-    width  = buffer->width;
-    height = buffer->height;
-    stride = buffer->stride;
-    format = buffer->format;
-    layerCount = buffer->layerCount;
-    usage  = buffer->usage;
-    handle = buffer->handle;
+    mInitCheck = initWithHandle(handle, method, width, height, format,
+            layerCount, producerUsage, consumerUsage, stride);
 }
 
 GraphicBuffer::~GraphicBuffer()
@@ -154,7 +114,6 @@
         allocator.free(handle);
     }
     handle = NULL;
-    mWrappedBuffer = 0;
 }
 
 status_t GraphicBuffer::initCheck() const {
@@ -192,8 +151,8 @@
         allocator.free(handle);
         handle = 0;
     }
-    return initSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, inUsage,
-            "[Reallocation]");
+    return initWithSize(inWidth, inHeight, inFormat, inLayerCount,
+            inUsage, inUsage, "[Reallocation]");
 }
 
 bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight,
@@ -207,7 +166,7 @@
     return false;
 }
 
-status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
+status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight,
         PixelFormat inFormat, uint32_t inLayerCount, uint64_t inProducerUsage,
         uint64_t inConsumerUsage, std::string requestorName)
 {
@@ -227,6 +186,54 @@
     return err;
 }
 
+status_t GraphicBuffer::initWithHandle(const native_handle_t* handle,
+        HandleWrapMethod method, uint32_t width, uint32_t height,
+        PixelFormat format, uint32_t layerCount,
+        uint64_t producerUsage, uint64_t consumerUsage,
+        uint32_t stride)
+{
+    native_handle_t* clone = nullptr;
+
+    if (method == CLONE_HANDLE) {
+        clone = native_handle_clone(handle);
+        if (!clone) {
+            return NO_MEMORY;
+        }
+
+        handle = clone;
+        method = TAKE_UNREGISTERED_HANDLE;
+    }
+
+    ANativeWindowBuffer::width  = static_cast<int>(width);
+    ANativeWindowBuffer::height = static_cast<int>(height);
+    ANativeWindowBuffer::stride = static_cast<int>(stride);
+    ANativeWindowBuffer::format = format;
+    ANativeWindowBuffer::usage  =
+        android_convertGralloc1To0Usage(producerUsage, consumerUsage);
+
+    ANativeWindowBuffer::layerCount = layerCount;
+    ANativeWindowBuffer::handle = handle;
+
+    mOwner = (method == WRAP_HANDLE) ? ownNone : ownHandle;
+
+    if (method == TAKE_UNREGISTERED_HANDLE) {
+        status_t err = mBufferMapper.registerBuffer(this);
+        if (err != NO_ERROR) {
+            // clean up cloned handle
+            if (clone) {
+                native_handle_close(clone);
+                native_handle_delete(clone);
+            }
+
+            initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0, 0);
+
+            return err;
+        }
+    }
+
+    return NO_ERROR;
+}
+
 status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr)
 {
     const Rect lockBounds(width, height);
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index aacc385..dfeed50 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -94,9 +94,12 @@
   }
 
   IonBuffer* buffer() { return &slices_[0]; }
+  const IonBuffer* buffer() const { return &slices_[0]; }
+
   // If index is greater than or equal to slice_count(), the result is
   // undefined.
   IonBuffer* slice(size_t index) { return &slices_[index]; }
+  const IonBuffer* slice(size_t index) const { return &slices_[index]; }
 
   int slice_count() const { return static_cast<int>(slices_.size()); }
   int id() const { return id_; }
@@ -171,9 +174,8 @@
   int Post(const LocalHandle& ready_fence) {
     return Post(ready_fence, nullptr, 0);
   }
-  template <
-      typename Meta,
-      typename = typename std::enable_if<!std::is_void<Meta>::value>::type>
+  template <typename Meta, typename = typename std::enable_if<
+                               !std::is_void<Meta>::value>::type>
   int Post(const LocalHandle& ready_fence, const Meta& meta) {
     return Post(ready_fence, &meta, sizeof(meta));
   }
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index ed11551..7ed024f 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -119,6 +119,14 @@
 using LocalFence = FenceHandle<pdx::LocalHandle>;
 using BorrowedFence = FenceHandle<pdx::BorrowedHandle>;
 
+struct QueueInfo {
+  size_t meta_size_bytes;
+  int id;
+
+ private:
+  PDX_SERIALIZABLE_MEMBERS(QueueInfo, meta_size_bytes, id);
+};
+
 // BufferHub Service RPC interface. Defines the endpoints, op codes, and method
 // type signatures supported by bufferhubd.
 struct BufferHubRPC {
@@ -151,6 +159,7 @@
     kOpConsumerSetIgnore,
     kOpCreateProducerQueue,
     kOpCreateConsumerQueue,
+    kOpGetQueueInfo,
     kOpProducerQueueAllocateBuffers,
     kOpProducerQueueDetachBuffer,
     kOpConsumerQueueImportBuffers,
@@ -192,18 +201,19 @@
 
   // Buffer Queue Methods.
   PDX_REMOTE_METHOD(CreateProducerQueue, kOpCreateProducerQueue,
-                    int(size_t meta_size_bytes, int usage_set_mask,
-                        int usage_clear_mask, int usage_deny_set_mask,
-                        int usage_deny_clear_mask));
+                    QueueInfo(size_t meta_size_bytes, int usage_set_mask,
+                              int usage_clear_mask, int usage_deny_set_mask,
+                              int usage_deny_clear_mask));
   PDX_REMOTE_METHOD(CreateConsumerQueue, kOpCreateConsumerQueue,
-                    std::pair<LocalChannelHandle, size_t>(Void));
+                    LocalChannelHandle(Void));
+  PDX_REMOTE_METHOD(GetQueueInfo, kOpGetQueueInfo, QueueInfo(Void));
   PDX_REMOTE_METHOD(ProducerQueueAllocateBuffers,
                     kOpProducerQueueAllocateBuffers,
                     std::vector<std::pair<LocalChannelHandle, size_t>>(
                         int width, int height, int format, int usage,
                         size_t slice_count, size_t buffer_count));
   PDX_REMOTE_METHOD(ProducerQueueDetachBuffer, kOpProducerQueueDetachBuffer,
-                    int(size_t slot));
+                    void(size_t slot));
   PDX_REMOTE_METHOD(ConsumerQueueImportBuffers, kOpConsumerQueueImportBuffers,
                     std::vector<std::pair<LocalChannelHandle, size_t>>(Void));
 };
diff --git a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
index e449cbd..ffc42d6 100644
--- a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
@@ -60,21 +60,20 @@
   int LockYUV(int usage, int x, int y, int width, int height,
               struct android_ycbcr* yuv);
   int Unlock();
-  buffer_handle_t handle() const { if (buffer_.get()) return buffer_->handle;
-                                   else return nullptr; }
-  int width() const { if (buffer_.get()) return buffer_->getWidth();
-                      else return 0; }
-  int height() const { if (buffer_.get()) return buffer_->getHeight();
-                       else return 0; }
-  int layer_count() const { if (buffer_.get()) return buffer_->getLayerCount();
-                            else return 0; }
-  int stride() const { if (buffer_.get()) return buffer_->getStride();
-                       else return 0; }
+
+  const sp<GraphicBuffer>& buffer() const { return buffer_; }
+  buffer_handle_t handle() const {
+    return buffer_.get() ? buffer_->handle : nullptr;
+  }
+  int width() const { return buffer_.get() ? buffer_->getWidth() : 0; }
+  int height() const { return buffer_.get() ? buffer_->getHeight() : 0; }
+  int layer_count() const {
+    return buffer_.get() ? buffer_->getLayerCount() : 0;
+  }
+  int stride() const { return buffer_.get() ? buffer_->getStride() : 0; }
   int layer_stride() const { return 0; }
-  int format() const { if (buffer_.get()) return buffer_->getPixelFormat();
-                       else return 0; }
-  int usage() const { if (buffer_.get()) return buffer_->getUsage();
-                      else return 0; }
+  int format() const { return buffer_.get() ? buffer_->getPixelFormat() : 0; }
+  int usage() const { return buffer_.get() ? buffer_->getUsage() : 0; }
 
  private:
   sp<GraphicBuffer> buffer_;
diff --git a/libs/vr/libbufferhub/ion_buffer.cpp b/libs/vr/libbufferhub/ion_buffer.cpp
index 3fb3f3c..e5a56c1 100644
--- a/libs/vr/libbufferhub/ion_buffer.cpp
+++ b/libs/vr/libbufferhub/ion_buffer.cpp
@@ -1,5 +1,4 @@
 #include <private/dvr/ion_buffer.h>
-#include <ui/GraphicBufferMapper.h>
 
 #include <log/log.h>
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -70,10 +69,9 @@
   ALOGD_IF(TRACE, "IonBuffer::Alloc: width=%d height=%d format=%d usage=%d",
            width, height, format, usage);
 
-  GraphicBufferMapper& mapper = GraphicBufferMapper::get();
   buffer_ = new GraphicBuffer(width, height, format, usage);
-  if (mapper.registerBuffer(buffer_.get()) != OK) {
-    ALOGE("IonBuffer::Aloc: Failed to register buffer");
+  if (buffer_->initCheck() != OK) {
+    ALOGE("IonBuffer::Aloc: Failed to allocate buffer");
   }
   return 0;
 }
@@ -96,11 +94,10 @@
       "usage=%d",
       handle, width, height, stride, format, usage);
   FreeHandle();
-  GraphicBufferMapper& mapper = GraphicBufferMapper::get();
-  buffer_ = new GraphicBuffer(width, height, format, 1, usage,
-                              stride, (native_handle_t*)handle, true);
-  if (mapper.registerBuffer(buffer_.get()) != OK) {
-    ALOGE("IonBuffer::Import: Failed to register cloned buffer");
+  buffer_ = new GraphicBuffer(handle, GraphicBuffer::TAKE_UNREGISTERED_HANDLE,
+          width, height, format, 1, usage, stride);
+  if (buffer_->initCheck() != OK) {
+    ALOGE("IonBuffer::Import: Failed to import buffer");
     return -EINVAL;
   }
   return 0;
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 031401a..e491abc 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -11,34 +11,36 @@
 #include <pdx/file_handle.h>
 #include <private/dvr/bufferhub_rpc.h>
 
+using android::pdx::ErrorStatus;
+using android::pdx::LocalChannelHandle;
+using android::pdx::Status;
+
 namespace android {
 namespace dvr {
 
-BufferHubQueue::BufferHubQueue(LocalChannelHandle channel_handle,
-                               size_t meta_size)
+BufferHubQueue::BufferHubQueue(LocalChannelHandle channel_handle)
     : Client{pdx::default_transport::ClientChannel::Create(
           std::move(channel_handle))},
-      meta_size_(meta_size),
-      meta_buffer_tmp_(meta_size ? new uint8_t[meta_size] : nullptr),
+      meta_size_(0),
       buffers_(BufferHubQueue::kMaxQueueCapacity),
       epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
       available_buffers_(BufferHubQueue::kMaxQueueCapacity),
       fences_(BufferHubQueue::kMaxQueueCapacity),
-      capacity_(0) {
+      capacity_(0),
+      id_(-1) {
   Initialize();
 }
 
-BufferHubQueue::BufferHubQueue(const std::string& endpoint_path,
-                               size_t meta_size)
+BufferHubQueue::BufferHubQueue(const std::string& endpoint_path)
     : Client{pdx::default_transport::ClientChannelFactory::Create(
           endpoint_path)},
-      meta_size_(meta_size),
-      meta_buffer_tmp_(meta_size ? new uint8_t[meta_size] : nullptr),
+      meta_size_(0),
       buffers_(BufferHubQueue::kMaxQueueCapacity),
       epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
       available_buffers_(BufferHubQueue::kMaxQueueCapacity),
       fences_(BufferHubQueue::kMaxQueueCapacity),
-      capacity_(0) {
+      capacity_(0),
+      id_(-1) {
   Initialize();
 }
 
@@ -55,26 +57,47 @@
                                     BufferHubQueue::kEpollQueueEventIndex)}};
   ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event);
   if (ret < 0) {
-    ALOGE("Failed to register ConsumerQueue into epoll event: %s",
+    ALOGE("BufferHubQueue::Initialize: Failed to add event fd to epoll set: %s",
           strerror(-ret));
   }
 }
 
-std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() {
-  Status<std::pair<LocalChannelHandle, size_t>> status =
-      InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>();
-
+Status<void> BufferHubQueue::ImportQueue() {
+  auto status = InvokeRemoteMethod<BufferHubRPC::GetQueueInfo>();
   if (!status) {
-    ALOGE("Cannot create ConsumerQueue: %s", status.GetErrorMessage().c_str());
+    ALOGE("BufferHubQueue::ImportQueue: Failed to import queue: %s",
+          status.GetErrorMessage().c_str());
+    return ErrorStatus(status.error());
+  } else {
+    SetupQueue(status.get().meta_size_bytes, status.get().id);
+    return {};
+  }
+}
+
+void BufferHubQueue::SetupQueue(size_t meta_size_bytes, int id) {
+  meta_size_ = meta_size_bytes;
+  id_ = id;
+  meta_buffer_tmp_.reset(meta_size_ > 0 ? new uint8_t[meta_size_] : nullptr);
+}
+
+std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() {
+  if (auto status = CreateConsumerQueueHandle())
+    return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
+  else
     return nullptr;
+}
+
+Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle() {
+  auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>();
+  if (!status) {
+    ALOGE(
+        "BufferHubQueue::CreateConsumerQueue: Failed to create consumer queue: "
+        "%s",
+        status.GetErrorMessage().c_str());
+    return ErrorStatus(status.error());
   }
 
-  auto return_value = status.take();
-
-  ALOGD_IF(TRACE, "BufferHubQueue::CreateConsumerQueue: meta_size_bytes=%zu",
-           return_value.second);
-  return ConsumerQueue::Create(std::move(return_value.first),
-                               return_value.second);
+  return status;
 }
 
 bool BufferHubQueue::WaitForBuffers(int timeout) {
@@ -89,7 +112,8 @@
     }
 
     if (ret < 0 && ret != -EINTR) {
-      ALOGE("Failed to wait for buffers: %s", strerror(-ret));
+      ALOGE("BufferHubQueue::WaitForBuffers: Failed to wait for buffers: %s",
+            strerror(-ret));
       return false;
     }
 
@@ -108,7 +132,8 @@
       } else if (is_queue_event_index(index)) {
         HandleQueueEvent(events[i]);
       } else {
-        ALOGW("Unknown event index: %" PRId64, index);
+        ALOGW("BufferHubQueue::WaitForBuffers: Unknown event index: %" PRId64,
+              index);
       }
     }
   }
@@ -134,7 +159,8 @@
   if (events & EPOLLIN) {
     int ret = OnBufferReady(buffer, &fences_[slot]);
     if (ret < 0) {
-      ALOGE("Failed to set buffer ready: %s", strerror(-ret));
+      ALOGE("BufferHubQueue::HandleBufferEvent: Failed to set buffer ready: %s",
+            strerror(-ret));
       return;
     }
     Enqueue(buffer, slot);
@@ -144,8 +170,8 @@
     // epoll FD is cleaned up when the replacement consumer client is imported,
     // we shouldn't detach again if |epollhub_pending_[slot]| is set.
     ALOGW(
-        "Receives EPOLLHUP at slot: %zu, buffer event fd: %d, EPOLLHUP "
-        "pending: %d",
+        "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP at slot: %zu, "
+        "buffer event fd: %d, EPOLLHUP pending: %d",
         slot, buffer->event_fd(), int{epollhup_pending_[slot]});
     if (epollhup_pending_[slot]) {
       epollhup_pending_[slot] = false;
@@ -153,7 +179,10 @@
       DetachBuffer(slot);
     }
   } else {
-    ALOGW("Unknown event, slot=%zu, epoll events=%d", slot, events);
+    ALOGW(
+        "BufferHubQueue::HandleBufferEvent: Unknown event, slot=%zu, epoll "
+        "events=%d",
+        slot, events);
   }
 }
 
@@ -169,12 +198,13 @@
   if (events & EPOLLIN) {
     // Note that after buffer imports, if |count()| still returns 0, epoll
     // wait will be tried again to acquire the newly imported buffer.
-    int ret = OnBufferAllocated();
-    if (ret < 0) {
-      ALOGE("Failed to import buffer: %s", strerror(-ret));
+    auto buffer_status = OnBufferAllocated();
+    if (!buffer_status) {
+      ALOGE("BufferHubQueue::HandleQueueEvent: Failed to import buffer: %s",
+            buffer_status.GetErrorMessage().c_str());
     }
   } else {
-    ALOGW("Unknown epoll events=%d", events);
+    ALOGW("BufferHubQueue::HandleQueueEvent: Unknown epoll events=%d", events);
   }
 }
 
@@ -233,7 +263,7 @@
 void BufferHubQueue::Enqueue(std::shared_ptr<BufferHubBuffer> buf,
                              size_t slot) {
   if (count() == capacity_) {
-    ALOGE("Buffer queue is full!");
+    ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!");
     return;
   }
 
@@ -274,7 +304,7 @@
   available_buffers_.PopFront();
 
   if (!buf) {
-    ALOGE("Dequeue: Buffer to be dequeued is nullptr");
+    ALOGE("BufferHubQueue::Dequeue: Buffer to be dequeued is nullptr");
     return nullptr;
   }
 
@@ -289,15 +319,22 @@
 ProducerQueue::ProducerQueue(size_t meta_size)
     : ProducerQueue(meta_size, 0, 0, 0, 0) {}
 
-ProducerQueue::ProducerQueue(LocalChannelHandle handle, size_t meta_size)
-    : BASE(std::move(handle), meta_size) {}
+ProducerQueue::ProducerQueue(LocalChannelHandle handle)
+    : BASE(std::move(handle)) {
+  auto status = ImportQueue();
+  if (!status) {
+    ALOGE("ProducerQueue::ProducerQueue: Failed to import queue: %s",
+          status.GetErrorMessage().c_str());
+    Close(-status.error());
+  }
+}
 
 ProducerQueue::ProducerQueue(size_t meta_size, int usage_set_mask,
                              int usage_clear_mask, int usage_deny_set_mask,
                              int usage_deny_clear_mask)
-    : BASE(BufferHubRPC::kClientPath, meta_size) {
+    : BASE(BufferHubRPC::kClientPath) {
   auto status = InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>(
-      meta_size_, usage_set_mask, usage_clear_mask, usage_deny_set_mask,
+      meta_size, usage_set_mask, usage_clear_mask, usage_deny_set_mask,
       usage_deny_clear_mask);
   if (!status) {
     ALOGE("ProducerQueue::ProducerQueue: Failed to create producer queue: %s",
@@ -305,12 +342,14 @@
     Close(-status.error());
     return;
   }
+
+  SetupQueue(status.get().meta_size_bytes, status.get().id);
 }
 
 int ProducerQueue::AllocateBuffer(int width, int height, int format, int usage,
                                   size_t slice_count, size_t* out_slot) {
   if (out_slot == nullptr) {
-    ALOGE("Parameter out_slot cannot be null.");
+    ALOGE("ProducerQueue::AllocateBuffer: Parameter out_slot cannot be null.");
     return -EINVAL;
   }
 
@@ -362,7 +401,7 @@
 }
 
 int ProducerQueue::DetachBuffer(size_t slot) {
-  Status<int> status =
+  auto status =
       InvokeRemoteMethod<BufferHubRPC::ProducerQueueDetachBuffer>(slot);
   if (!status) {
     ALOGE(
@@ -378,7 +417,9 @@
 std::shared_ptr<BufferProducer> ProducerQueue::Dequeue(
     int timeout, size_t* slot, LocalHandle* release_fence) {
   if (slot == nullptr || release_fence == nullptr) {
-    ALOGE("invalid parameter, slot=%p, release_fence=%p", slot, release_fence);
+    ALOGE(
+        "ProducerQueue::Dequeue: invalid parameter, slot=%p, release_fence=%p",
+        slot, release_fence);
     return nullptr;
   }
 
@@ -392,21 +433,27 @@
   return buffer->Gain(release_fence);
 }
 
-ConsumerQueue::ConsumerQueue(LocalChannelHandle handle, size_t meta_size)
-    : BASE(std::move(handle), meta_size) {
-  // TODO(b/34387835) Import consumer queue in case the ProducerQueue we are
+ConsumerQueue::ConsumerQueue(LocalChannelHandle handle)
+    : BufferHubQueue(std::move(handle)) {
+  auto status = ImportQueue();
+  if (!status) {
+    ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s",
+          status.GetErrorMessage().c_str());
+    Close(-status.error());
+  }
+
+  // TODO(b/34387835) Import buffers in case the ProducerQueue we are
   // based on was not empty.
 }
 
-int ConsumerQueue::ImportBuffers() {
-  Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status =
-      InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
+Status<size_t> ConsumerQueue::ImportBuffers() {
+  auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
   if (!status) {
     ALOGE(
         "ConsumerQueue::ImportBuffers failed to import consumer buffer through "
         "BufferBub, error: %s",
         status.GetErrorMessage().c_str());
-    return -status.error();
+    return ErrorStatus(status.error());
   }
 
   int last_error = 0;
@@ -431,7 +478,10 @@
     }
   }
 
-  return imported_buffers > 0 ? imported_buffers : last_error;
+  if (imported_buffers > 0)
+    return {imported_buffers};
+  else
+    return ErrorStatus(-last_error);
 }
 
 int ConsumerQueue::AddBuffer(const std::shared_ptr<BufferConsumer>& buf,
@@ -445,15 +495,17 @@
     LocalHandle* acquire_fence) {
   if (meta_size != meta_size_) {
     ALOGE(
-        "metadata size (%zu) for the dequeuing buffer does not match metadata "
-        "size (%zu) for the queue.",
+        "ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer "
+        "does not match metadata size (%zu) for the queue.",
         meta_size, meta_size_);
     return nullptr;
   }
 
   if (slot == nullptr || meta == nullptr || acquire_fence == nullptr) {
-    ALOGE("invalid parameter, slot=%p, meta=%p, acquire_fence=%p", slot, meta,
-          acquire_fence);
+    ALOGE(
+        "ConsumerQueue::Dequeue: Invalid parameter, slot=%p, meta=%p, "
+        "acquire_fence=%p",
+        slot, meta, acquire_fence);
     return nullptr;
   }
 
@@ -467,15 +519,19 @@
   return buffer->Acquire(acquire_fence, meta_buffer_tmp_.get(), meta_size_);
 }
 
-int ConsumerQueue::OnBufferAllocated() {
-  const int ret = ImportBuffers();
-  if (ret == 0) {
-    ALOGW("No new buffer can be imported on buffer allocated event.");
-  } else if (ret < 0) {
-    ALOGE("Failed to import buffers on buffer allocated event.");
+Status<void> ConsumerQueue::OnBufferAllocated() {
+  auto status = ImportBuffers();
+  if (!status) {
+    ALOGE("ConsumerQueue::OnBufferAllocated: Failed to import buffers: %s",
+          status.GetErrorMessage().c_str());
+    return ErrorStatus(status.error());
+  } else if (status.get() == 0) {
+    ALOGW("ConsumerQueue::OnBufferAllocated: No new buffers allocated!");
+    return ErrorStatus(ENOBUFS);
+  } else {
+    ALOGD_IF(TRACE, "Imported %zu consumer buffers.", status.get());
+    return {};
   }
-  ALOGD_IF(TRACE, "Imported %d consumer buffers.", ret);
-  return ret;
 }
 
 }  // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
index a108042..a826a69 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
@@ -50,27 +50,7 @@
   LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr,
                       "Failed to get buffer producer at slot: %zu", slot);
 
-  // Allocating a new buffer, |buffers_[slot]| should be in initial state.
-  LOG_ALWAYS_FATAL_IF(buffers_[slot].mGraphicBuffer != nullptr,
-                      "AllocateBuffer: slot %zu is not empty.", slot);
-
-  // Create new GraphicBuffer based on the newly created |buffer_producer|. Here
-  // we have to cast |buffer_handle_t| to |native_handle_t|, it's OK because
-  // internally, GraphicBuffer is still an |ANativeWindowBuffer| and |handle|
-  // is still type of |buffer_handle_t| and bears const property.
-  sp<GraphicBuffer> graphic_buffer(new GraphicBuffer(
-      buffer_producer->width(), buffer_producer->height(),
-      buffer_producer->format(),
-      1, /* layer count */
-      buffer_producer->usage(),
-      buffer_producer->stride(),
-      const_cast<native_handle_t*>(buffer_producer->buffer()->handle()),
-      false));
-
-  LOG_ALWAYS_FATAL_IF(NO_ERROR != graphic_buffer->initCheck(),
-                      "Failed to init GraphicBuffer.");
   buffers_[slot].mBufferProducer = buffer_producer;
-  buffers_[slot].mGraphicBuffer = graphic_buffer;
 
   return NO_ERROR;
 }
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index ddf7fd2..3fe7642 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -8,7 +8,7 @@
 
 BufferHubQueueProducer::BufferHubQueueProducer(
     const std::shared_ptr<BufferHubQueueCore>& core)
-    : core_(core), req_buffer_count_(kInvalidBufferCount) {}
+    : core_(core) {}
 
 status_t BufferHubQueueProducer::requestBuffer(int slot,
                                                sp<GraphicBuffer>* buf) {
@@ -16,18 +16,48 @@
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
-  if (slot < 0 || slot >= req_buffer_count_) {
+  if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) {
+    ALOGE("requestBuffer: BufferHubQueueProducer has no connected producer");
+    return NO_INIT;
+  }
+
+  if (slot < 0 || slot >= max_buffer_count_) {
     ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot,
-          req_buffer_count_);
+          max_buffer_count_);
     return BAD_VALUE;
   } else if (!core_->buffers_[slot].mBufferState.isDequeued()) {
     ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)",
           slot, core_->buffers_[slot].mBufferState.string());
     return BAD_VALUE;
+  } else if (core_->buffers_[slot].mGraphicBuffer != nullptr) {
+    ALOGE("requestBuffer: slot %d is not empty.", slot);
+    return BAD_VALUE;
+  } else if (core_->buffers_[slot].mBufferProducer == nullptr) {
+    ALOGE("requestBuffer: slot %d is not dequeued.", slot);
+    return BAD_VALUE;
   }
 
+  const auto& buffer_producer = core_->buffers_[slot].mBufferProducer;
+
+  // Create new GraphicBuffer based on the newly created |buffer_producer|. Here
+  // we have to cast |buffer_handle_t| to |native_handle_t|, it's OK because
+  // internally, GraphicBuffer is still an |ANativeWindowBuffer| and |handle|
+  // is still type of |buffer_handle_t| and bears const property.
+  sp<GraphicBuffer> graphic_buffer(new GraphicBuffer(
+      buffer_producer->width(), buffer_producer->height(),
+      buffer_producer->format(),
+      1, /* layer count */
+      buffer_producer->usage(),
+      buffer_producer->stride(),
+      const_cast<native_handle_t*>(buffer_producer->buffer()->handle()),
+      false));
+
+  LOG_ALWAYS_FATAL_IF(NO_ERROR != graphic_buffer->initCheck(),
+                      "Failed to init GraphicBuffer.");
+  core_->buffers_[slot].mGraphicBuffer = graphic_buffer;
   core_->buffers_[slot].mRequestBufferCalled = true;
-  *buf = core_->buffers_[slot].mGraphicBuffer;
+
+  *buf = graphic_buffer;
   return NO_ERROR;
 }
 
@@ -46,30 +76,68 @@
     return BAD_VALUE;
   }
 
-  req_buffer_count_ = max_dequeued_buffers;
+  // The new dequeued_buffers count should not be violated by the number
+  // of currently dequeued buffers.
+  int dequeued_count = 0;
+  for (const auto& buf : core_->buffers_) {
+    if (buf.mBufferState.isDequeued()) {
+      dequeued_count++;
+    }
+  }
+  if (dequeued_count > max_dequeued_buffers) {
+    ALOGE(
+        "setMaxDequeuedBufferCount: the requested dequeued_buffers"
+        "count (%d) exceeds the current dequeued buffer count (%d)",
+        max_dequeued_buffers, dequeued_count);
+    return BAD_VALUE;
+  }
+
+  max_dequeued_buffer_count_ = max_dequeued_buffers;
   return NO_ERROR;
 }
 
-status_t BufferHubQueueProducer::setAsyncMode(bool /* async */) {
-  ALOGE("BufferHubQueueProducer::setAsyncMode not implemented.");
-  return INVALID_OPERATION;
+status_t BufferHubQueueProducer::setAsyncMode(bool async) {
+  if (async) {
+    // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer
+    // automatically and behaves differently from IGraphicBufferConsumer. Thus,
+    // android::BufferQueue's async mode (a.k.a. allocating an additional buffer
+    // to prevent dequeueBuffer from being blocking) technically does not apply
+    // here.
+    //
+    // In Daydream, non-blocking producer side dequeue is guaranteed by careful
+    // buffer consumer implementations. In another word, BufferHubQueue based
+    // dequeueBuffer should never block whether setAsyncMode(true) is set or
+    // not.
+    //
+    // See: IGraphicBufferProducer::setAsyncMode and
+    // BufferQueueProducer::setAsyncMode for more about original implementation.
+    ALOGW(
+        "BufferHubQueueProducer::setAsyncMode: BufferHubQueue should always be "
+        "asynchronous. This call makes no effact.");
+    return NO_ERROR;
+  }
+  return NO_ERROR;
 }
 
-status_t BufferHubQueueProducer::dequeueBuffer(int* out_slot,
-                                               sp<Fence>* out_fence,
-                                               uint32_t width, uint32_t height,
-                                               PixelFormat format,
-                                               uint32_t usage,
-                                               FrameEventHistoryDelta* /* outTimestamps */) {
+status_t BufferHubQueueProducer::dequeueBuffer(
+    int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
+    PixelFormat format, uint32_t usage,
+    FrameEventHistoryDelta* /* out_timestamps */) {
   ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width,
            height, format, usage);
 
   status_t ret;
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
-  if (static_cast<int32_t>(core_->producer_->capacity()) < req_buffer_count_) {
+  if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) {
+    ALOGE("dequeueBuffer: BufferQueue has no connected producer");
+    return NO_INIT;
+  }
+
+  if (static_cast<int32_t>(core_->producer_->capacity()) <
+      max_dequeued_buffer_count_) {
     // Lazy allocation. When the capacity of |core_->producer_| has not reach
-    // |req_buffer_count_|, allocate new buffer.
+    // |max_dequeued_buffer_count_|, allocate new buffer.
     // TODO(jwcai) To save memory, the really reasonable thing to do is to go
     // over existing slots and find first existing one to dequeue.
     ret = core_->AllocateBuffer(width, height, format, usage, 1);
@@ -126,8 +194,8 @@
   // BufferHubQueue).
   // TODO(jwcai) Clean this up, make mBufferState compatible with BufferHub's
   // model.
-  LOG_ALWAYS_FATAL_IF(!core_->buffers_[slot].mBufferState.isFree() &&
-                          !core_->buffers_[slot].mBufferState.isQueued(),
+  LOG_ALWAYS_FATAL_IF((!core_->buffers_[slot].mBufferState.isFree() &&
+                       !core_->buffers_[slot].mBufferState.isQueued()),
                       "dequeueBuffer: slot %zu is not free or queued.", slot);
 
   core_->buffers_[slot].mBufferState.freeQueued();
@@ -170,22 +238,39 @@
 
 status_t BufferHubQueueProducer::queueBuffer(int slot,
                                              const QueueBufferInput& input,
-                                             QueueBufferOutput* /* output */) {
+                                             QueueBufferOutput* output) {
   ALOGD_IF(TRACE, "queueBuffer: slot %d", slot);
 
+  if (output == nullptr) {
+    return BAD_VALUE;
+  }
+
   int64_t timestamp;
+  int scaling_mode;
   sp<Fence> fence;
+  Rect crop(Rect::EMPTY_RECT);
 
   // TODO(jwcai) The following attributes are ignored.
   bool is_auto_timestamp;
   android_dataspace data_space;
-  Rect crop(Rect::EMPTY_RECT);
-  int scaling_mode;
   uint32_t transform;
 
   input.deflate(&timestamp, &is_auto_timestamp, &data_space, &crop,
                 &scaling_mode, &transform, &fence);
 
+  // Check input scaling mode is valid.
+  switch (scaling_mode) {
+    case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+    case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+    case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+    case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+      break;
+    default:
+      ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode);
+      return BAD_VALUE;
+  }
+
+  // Check input fence is valid.
   if (fence == nullptr) {
     ALOGE("queueBuffer: fence is NULL");
     return BAD_VALUE;
@@ -194,25 +279,61 @@
   status_t ret;
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
-  if (slot < 0 || slot >= req_buffer_count_) {
+  if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) {
+    ALOGE("queueBuffer: BufferQueue has no connected producer");
+    return NO_INIT;
+  }
+
+  if (slot < 0 || slot >= max_buffer_count_) {
     ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot,
-          req_buffer_count_);
+          max_buffer_count_);
     return BAD_VALUE;
   } else if (!core_->buffers_[slot].mBufferState.isDequeued()) {
     ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)",
           slot, core_->buffers_[slot].mBufferState.string());
     return BAD_VALUE;
+  } else if ((!core_->buffers_[slot].mRequestBufferCalled ||
+              core_->buffers_[slot].mGraphicBuffer == nullptr)) {
+    ALOGE(
+        "queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, "
+        "mGraphicBuffer=%p)",
+        slot, core_->buffers_[slot].mRequestBufferCalled,
+        core_->buffers_[slot].mGraphicBuffer.get());
+    return BAD_VALUE;
   }
 
   // Post the buffer producer with timestamp in the metadata.
-  auto buffer_producer = core_->buffers_[slot].mBufferProducer;
+  const auto& buffer_producer = core_->buffers_[slot].mBufferProducer;
+
+  // Check input crop is not out of boundary of current buffer.
+  Rect buffer_rect(buffer_producer->width(), buffer_producer->height());
+  Rect cropped_rect(Rect::EMPTY_RECT);
+  crop.intersect(buffer_rect, &cropped_rect);
+  if (cropped_rect != crop) {
+    ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot);
+    return BAD_VALUE;
+  }
+
   LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
 
   BufferHubQueueCore::BufferMetadata meta_data = {.timestamp = timestamp};
   buffer_producer->Post(fence_fd, &meta_data, sizeof(meta_data));
   core_->buffers_[slot].mBufferState.queue();
 
-  // TODO(jwcai) check how to fill in output properly.
+  output->width = buffer_producer->width();
+  output->height = buffer_producer->height();
+  output->transformHint = 0; // default value, we don't use it yet.
+
+  // |numPendingBuffers| counts of the number of buffers that has been enqueued
+  // by the producer but not yet acquired by the consumer. Due to the nature
+  // of BufferHubQueue design, this is hard to trace from the producer's client
+  // side, but it's safe to assume it's zero.
+  output->numPendingBuffers = 0;
+
+  // Note that we are not setting nextFrameNumber here as it seems to be only
+  // used by surface flinger. See more at b/22802885, ag/791760.
+  output->nextFrameNumber = 0;
+
   return NO_ERROR;
 }
 
@@ -222,15 +343,20 @@
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
-  if (slot < 0 || slot >= req_buffer_count_) {
+  if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) {
+    ALOGE("cancelBuffer: BufferQueue has no connected producer");
+    return NO_INIT;
+  }
+
+  if (slot < 0 || slot >= max_buffer_count_) {
     ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot,
-          req_buffer_count_);
+          max_buffer_count_);
     return BAD_VALUE;
   } else if (!core_->buffers_[slot].mBufferState.isDequeued()) {
     ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)",
           slot, core_->buffers_[slot].mBufferState.string());
     return BAD_VALUE;
-  } else if (fence == NULL) {
+  } else if (fence == nullptr) {
     ALOGE("cancelBuffer: fence is NULL");
     return BAD_VALUE;
   }
@@ -249,7 +375,7 @@
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
-  if (out_value == NULL) {
+  if (out_value == nullptr) {
     ALOGE("query: out_value was NULL");
     return BAD_VALUE;
   }
@@ -262,15 +388,30 @@
     case NATIVE_WINDOW_BUFFER_AGE:
       value = 0;
       break;
+    case NATIVE_WINDOW_WIDTH:
+      value = core_->producer_->default_width();
+      break;
+    case NATIVE_WINDOW_HEIGHT:
+      value = core_->producer_->default_height();
+      break;
+    case NATIVE_WINDOW_FORMAT:
+      value = core_->producer_->default_format();
+      break;
+    case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
+      // BufferHubQueue is always operating in async mode, thus semantically
+      // consumer can never be running behind. See BufferQueueCore.cpp core
+      // for more information about the original meaning of this flag.
+      value = 0;
+      break;
+    case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+      // TODO(jwcai) This is currently not implement as we don't need
+      // IGraphicBufferConsumer parity.
+      value = 0;
+      break;
     // The following queries are currently considered as unsupported.
     // TODO(jwcai) Need to carefully check the whether they should be
     // supported after all.
-    case NATIVE_WINDOW_WIDTH:
-    case NATIVE_WINDOW_HEIGHT:
-    case NATIVE_WINDOW_FORMAT:
     case NATIVE_WINDOW_STICKY_TRANSFORM:
-    case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
-    case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
     case NATIVE_WINDOW_DEFAULT_DATASPACE:
     default:
       return BAD_VALUE;
@@ -282,24 +423,58 @@
 }
 
 status_t BufferHubQueueProducer::connect(
-    const sp<IProducerListener>& /* listener */, int /* api */,
-    bool /* producer_controlled_by_app */, QueueBufferOutput* /* output */) {
+    const sp<IProducerListener>& /* listener */, int api,
+    bool /* producer_controlled_by_app */, QueueBufferOutput* output) {
   // Consumer interaction are actually handled by buffer hub, and we need
-  // to maintain consumer operations here. Hence |connect| is a NO-OP.
+  // to maintain consumer operations here. We only need to perform basic input
+  // parameter checks here.
   ALOGD_IF(TRACE, __FUNCTION__);
+
+  if (output == nullptr) {
+    return BAD_VALUE;
+  }
+
+  std::unique_lock<std::mutex> lock(core_->mutex_);
+
+  if (core_->connected_api_ != BufferHubQueueCore::kNoConnectedApi) {
+    return BAD_VALUE;
+  }
+
+  switch (api) {
+    case NATIVE_WINDOW_API_EGL:
+    case NATIVE_WINDOW_API_CPU:
+    case NATIVE_WINDOW_API_MEDIA:
+    case NATIVE_WINDOW_API_CAMERA:
+      core_->connected_api_ = api;
+      // TODO(jwcai) Fill output.
+      break;
+    default:
+      ALOGE("BufferHubQueueProducer::connect: unknow API %d", api);
+      return BAD_VALUE;
+  }
+
   return NO_ERROR;
 }
 
-status_t BufferHubQueueProducer::disconnect(int /* api */, DisconnectMode /* mode */) {
+status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode mode) {
   // Consumer interaction are actually handled by buffer hub, and we need
-  // to maintain consumer operations here. Hence |disconnect| is a NO-OP.
+  // to maintain consumer operations here.  We only need to perform basic input
+  // parameter checks here.
   ALOGD_IF(TRACE, __FUNCTION__);
+
+  std::unique_lock<std::mutex> lock(core_->mutex_);
+
+  if (api != core_->connected_api_) {
+    return BAD_VALUE;
+  }
+
+  core_->connected_api_ = BufferHubQueueCore::kNoConnectedApi;
   return NO_ERROR;
 }
 
 status_t BufferHubQueueProducer::setSidebandStream(
     const sp<NativeHandle>& stream) {
-  if (stream != NULL) {
+  if (stream != nullptr) {
     // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's
     // metadata.
     ALOGE("SidebandStream is not currently supported.");
@@ -314,7 +489,7 @@
                                              uint32_t /* usage */) {
   // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
   // of buffers permitted by the current BufferQueue configuration (aka
-  // |req_buffer_count_|).
+  // |max_buffer_count_|).
   ALOGE("BufferHubQueueProducer::allocateBuffers not implemented.");
 }
 
@@ -343,6 +518,7 @@
 status_t BufferHubQueueProducer::setSharedBufferMode(
     bool /* shared_buffer_mode */) {
   ALOGE("BufferHubQueueProducer::setSharedBufferMode not implemented.");
+  // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
   return INVALID_OPERATION;
 }
 
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 f786356..2b70c5b 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
@@ -4,6 +4,7 @@
 #include <gui/BufferQueueDefs.h>
 
 #include <pdx/client.h>
+#include <pdx/status.h>
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/epoll_file_descriptor.h>
 #include <private/dvr/ring_buffer.h>
@@ -32,6 +33,18 @@
   // a new consumer queue client or nullptr on failure.
   std::unique_ptr<ConsumerQueue> CreateConsumerQueue();
 
+  // Return the default buffer width of this buffer queue.
+  size_t default_width() const { return default_width_; }
+
+  // Return the default buffer height of this buffer queue.
+  size_t default_height() const { return default_height_; }
+
+  // Return the default buffer format of this buffer queue.
+  int32_t default_format() const { return default_format_; }
+
+  // Create a new consumer in handle form for immediate transport over RPC.
+  Status<LocalChannelHandle> CreateConsumerQueueHandle();
+
   // Return the number of buffers avaiable for dequeue.
   size_t count() const { return available_buffers_.GetSize(); }
 
@@ -42,7 +55,7 @@
   size_t metadata_size() const { return meta_size_; }
 
   // Return whether the buffer queue is alrady full.
-  bool is_full() const { return  available_buffers_.IsFull(); }
+  bool is_full() const { return available_buffers_.IsFull(); }
 
   explicit operator bool() const { return epoll_fd_.IsValid(); }
 
@@ -74,9 +87,18 @@
   // timeout.
   static constexpr int kNoTimeOut = -1;
 
+  int id() const { return id_; }
+
  protected:
-  BufferHubQueue(LocalChannelHandle channel, size_t meta_size);
-  BufferHubQueue(const std::string& endpoint_path, size_t meta_size);
+  BufferHubQueue(LocalChannelHandle channel);
+  BufferHubQueue(const std::string& endpoint_path);
+
+  // Imports the queue parameters by querying BufferHub for the parameters for
+  // this channel.
+  Status<void> ImportQueue();
+
+  // Sets up the queue with the given parameters.
+  void SetupQueue(size_t meta_size_bytes_, int id);
 
   // Called by ProducerQueue::AddBuffer and ConsumerQueue::AddBuffer only. to
   // register a buffer for epoll and internal bookkeeping.
@@ -103,7 +125,7 @@
                             LocalHandle* fence) = 0;
 
   // Called when a buffer is allocated remotely.
-  virtual int OnBufferAllocated() = 0;
+  virtual Status<void> OnBufferAllocated() { return {}; }
 
   // Data members to handle arbitrary metadata passed through BufferHub. It is
   // fair to enforce that all buffers in the same queue share the same metadata
@@ -169,6 +191,18 @@
     void operator=(BufferInfo&) = delete;
   };
 
+  // Default buffer width that can be set to override the buffer width when a
+  // width and height of 0 are specified in AllocateBuffer.
+  size_t default_width_{1};
+
+  // Default buffer height that can be set to override the buffer height when a
+  // width and height of 0 are specified in AllocateBuffer.
+  size_t default_height_{1};
+
+  // Default buffer format that can be set to override the buffer format when it
+  // isn't specified in AllocateBuffer.
+  int32_t default_format_{PIXEL_FORMAT_RGBA_8888};
+
   // Buffer queue:
   // |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|.
   std::vector<std::shared_ptr<BufferHubBuffer>> buffers_;
@@ -214,6 +248,9 @@
   // Epoll fd used to wait for BufferHub events.
   EpollFileDescriptor epoll_fd_;
 
+  // Global id for the queue that is consistent across processes.
+  int id_;
+
   BufferHubQueue(const BufferHubQueue&) = delete;
   void operator=(BufferHubQueue&) = delete;
 };
@@ -246,9 +283,8 @@
   }
 
   // Import a |ProducerQueue| from a channel handle.
-  template <typename Meta>
   static std::unique_ptr<ProducerQueue> Import(LocalChannelHandle handle) {
-    return BASE::Create(std::move(handle), sizeof(Meta));
+    return BASE::Create(std::move(handle));
   }
 
   // Get a buffer producer. Note that the method doesn't check whether the
@@ -290,18 +326,15 @@
   // static template methods inherited from ClientBase, which take the same
   // arguments as the constructors.
   explicit ProducerQueue(size_t meta_size);
-  ProducerQueue(LocalChannelHandle handle, size_t meta_size);
+  ProducerQueue(LocalChannelHandle handle);
   ProducerQueue(size_t meta_size, int usage_set_mask, int usage_clear_mask,
                 int usage_deny_set_mask, int usage_deny_clear_mask);
 
   int OnBufferReady(std::shared_ptr<BufferHubBuffer> buf,
                     LocalHandle* release_fence) override;
-
-  // Producer buffer is always allocated from the client (i.e. local) side.
-  int OnBufferAllocated() override { return 0; }
 };
 
-class ConsumerQueue : public pdx::ClientBase<ConsumerQueue, BufferHubQueue> {
+class ConsumerQueue : public BufferHubQueue {
  public:
   // Get a buffer consumer. Note that the method doesn't check whether the
   // buffer slot has a valid buffer that has been imported already. When no
@@ -312,10 +345,14 @@
         BufferHubQueue::GetBuffer(slot));
   }
 
+  // Import a |ConsumerQueue| from a channel handle.
+  static std::unique_ptr<ConsumerQueue> Import(LocalChannelHandle handle) {
+    return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(std::move(handle)));
+  }
+
   // Import newly created buffers from the service side.
-  // Returns number of buffers successfully imported; or negative error code
-  // when buffer import fails.
-  int ImportBuffers();
+  // Returns number of buffers successfully imported or an error.
+  Status<size_t> ImportBuffers();
 
   // Dequeue a consumer buffer to read. The returned buffer in |Acquired|'ed
   // mode, and caller should call Releasse() once it's done writing to release
@@ -332,10 +369,11 @@
   std::shared_ptr<BufferConsumer> Dequeue(int timeout, size_t* slot, void* meta,
                                           size_t meta_size,
                                           LocalHandle* acquire_fence);
- private:
-  friend BASE;
 
-  ConsumerQueue(LocalChannelHandle handle, size_t meta_size);
+ private:
+  friend BufferHubQueue;
+
+  ConsumerQueue(LocalChannelHandle handle);
 
   // Add a consumer buffer to populate the queue. Once added, a consumer buffer
   // is NOT available to use until the producer side |Post| it. |WaitForBuffers|
@@ -346,7 +384,7 @@
   int OnBufferReady(std::shared_ptr<BufferHubBuffer> buf,
                     LocalHandle* acquire_fence) override;
 
-  int OnBufferAllocated() override;
+  Status<void> OnBufferAllocated() override;
 };
 
 }  // namespace dvr
@@ -360,6 +398,7 @@
 
 struct DvrWriteBufferQueue {
   std::shared_ptr<android::dvr::ProducerQueue> producer_queue_;
+  ANativeWindow* native_window_{nullptr};
 };
 
 struct DvrReadBufferQueue {
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h
index ba0c0c5..e353187 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h
@@ -17,6 +17,8 @@
   friend class BufferHubQueueProducer;
 
  public:
+  static constexpr int kNoConnectedApi = -1;
+
   // Create a BufferHubQueueCore instance by creating a new producer queue.
   static std::shared_ptr<BufferHubQueueCore> Create();
 
@@ -87,6 +89,9 @@
   // Mutex for thread safety.
   std::mutex mutex_;
 
+  // Connect client API, should be one of the NATIVE_WINDOW_API_* flags.
+  int connected_api_{kNoConnectedApi};
+
   // |buffers_| stores the buffers that have been dequeued from
   // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets
   // filled in with the result of |Dequeue|.
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
index 5b1a7e0..43e5ce3 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
@@ -103,13 +103,15 @@
  private:
   using LocalHandle = pdx::LocalHandle;
 
-  static constexpr int kInvalidBufferCount = -1;
-
   // |core_| holds the actually buffer slots.
   std::shared_ptr<BufferHubQueueCore> core_;
 
-  // |req_buffer_count_| sets the capacity of the underlying buffer queue.
-  int32_t req_buffer_count_;
+  // |max_buffer_count_| sets the capacity of the underlying buffer queue.
+  int32_t max_buffer_count_{BufferHubQueue::kMaxQueueCapacity};
+
+  // |max_dequeued_buffer_count_| set the maximum number of buffers that can
+  // be dequeued at the same momment.
+  int32_t max_dequeued_buffer_count_{1};
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 811543d..171577d 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -22,16 +22,20 @@
 class BufferHubQueueTest : public ::testing::Test {
  public:
   template <typename Meta>
-  void CreateQueues(int usage_set_mask = 0, int usage_clear_mask = 0,
+  bool CreateQueues(int usage_set_mask = 0, int usage_clear_mask = 0,
                     int usage_deny_set_mask = 0,
                     int usage_deny_clear_mask = 0) {
     producer_queue_ =
         ProducerQueue::Create<Meta>(usage_set_mask, usage_clear_mask,
                                     usage_deny_set_mask, usage_deny_clear_mask);
-    ASSERT_NE(nullptr, producer_queue_);
+    if (!producer_queue_)
+      return false;
 
     consumer_queue_ = producer_queue_->CreateConsumerQueue();
-    ASSERT_NE(nullptr, consumer_queue_);
+    if (!consumer_queue_)
+      return false;
+
+    return true;
   }
 
   void AllocateBuffer() {
@@ -51,7 +55,7 @@
 TEST_F(BufferHubQueueTest, TestDequeue) {
   const size_t nb_dequeue_times = 16;
 
-  CreateQueues<size_t>();
+  ASSERT_TRUE(CreateQueues<size_t>());
 
   // Allocate only one buffer.
   AllocateBuffer();
@@ -77,7 +81,7 @@
   size_t slot;
   uint64_t seq;
 
-  CreateQueues<uint64_t>();
+  ASSERT_TRUE(CreateQueues<uint64_t>());
 
   for (size_t i = 0; i < nb_buffer; i++) {
     AllocateBuffer();
@@ -127,7 +131,7 @@
 };
 
 TEST_F(BufferHubQueueTest, TestMetadata) {
-  CreateQueues<TestMetadata>();
+  ASSERT_TRUE(CreateQueues<TestMetadata>());
   AllocateBuffer();
 
   std::vector<TestMetadata> ms = {
@@ -149,7 +153,7 @@
 }
 
 TEST_F(BufferHubQueueTest, TestMetadataMismatch) {
-  CreateQueues<int64_t>();
+  ASSERT_TRUE(CreateQueues<int64_t>());
   AllocateBuffer();
 
   int64_t mi = 3;
@@ -166,7 +170,7 @@
 }
 
 TEST_F(BufferHubQueueTest, TestEnqueue) {
-  CreateQueues<int64_t>();
+  ASSERT_TRUE(CreateQueues<int64_t>());
   AllocateBuffer();
 
   size_t slot;
@@ -181,7 +185,7 @@
 }
 
 TEST_F(BufferHubQueueTest, TestAllocateBuffer) {
-  CreateQueues<int64_t>();
+  ASSERT_TRUE(CreateQueues<int64_t>());
 
   size_t s1;
   AllocateBuffer();
@@ -227,7 +231,7 @@
 
 TEST_F(BufferHubQueueTest, TestUsageSetMask) {
   const int set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  CreateQueues<int64_t>(set_mask, 0, 0, 0);
+  ASSERT_TRUE(CreateQueues<int64_t>(set_mask, 0, 0, 0));
 
   // When allocation, leave out |set_mask| from usage bits on purpose.
   size_t slot;
@@ -243,7 +247,7 @@
 
 TEST_F(BufferHubQueueTest, TestUsageClearMask) {
   const int clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  CreateQueues<int64_t>(0, clear_mask, 0, 0);
+  ASSERT_TRUE(CreateQueues<int64_t>(0, clear_mask, 0, 0));
 
   // When allocation, add |clear_mask| into usage bits on purpose.
   size_t slot;
@@ -259,7 +263,7 @@
 
 TEST_F(BufferHubQueueTest, TestUsageDenySetMask) {
   const int deny_set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  CreateQueues<int64_t>(0, 0, deny_set_mask, 0);
+  ASSERT_TRUE(CreateQueues<int64_t>(0, 0, deny_set_mask, 0));
 
   // Now that |deny_set_mask| is illegal, allocation without those bits should
   // be able to succeed.
@@ -278,7 +282,7 @@
 
 TEST_F(BufferHubQueueTest, TestUsageDenyClearMask) {
   const int deny_clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  CreateQueues<int64_t>(0, 0, 0, deny_clear_mask);
+  ASSERT_TRUE(CreateQueues<int64_t>(0, 0, 0, deny_clear_mask));
 
   // Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are
   // mandatory), allocation with those bits should be able to succeed.
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index 5bb121a..64034e8 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -1,7 +1,9 @@
 #include <private/dvr/buffer_hub_queue_producer.h>
 
 #include <base/logging.h>
+#include <gui/IProducerListener.h>
 #include <gui/Surface.h>
+
 #include <gtest/gtest.h>
 
 namespace android {
@@ -9,12 +11,500 @@
 
 namespace {
 
-class BufferHubQueueProducerTest : public ::testing::Test {};
+// Default dimensions before setDefaultBufferSize is called by the consumer.
+constexpr uint32_t kDefaultWidth = 1;
+constexpr uint32_t kDefaultHeight = 1;
 
-TEST_F(BufferHubQueueProducerTest, TempTestBufferHubQueueProducer) {
-  auto core = BufferHubQueueCore::Create();
-  sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer(core);
-  sp<Surface> surface = new Surface(producer, true);
+// Default format before setDefaultBufferFormat is called by the consumer.
+constexpr PixelFormat kDefaultFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+constexpr int kDefaultConsumerUsageBits = 0;
+
+// Default transform hint before setTransformHint is called by the consumer.
+constexpr uint32_t kDefaultTransformHint = 0;
+
+constexpr int kTestApi = NATIVE_WINDOW_API_CPU;
+constexpr int kTestApiOther = NATIVE_WINDOW_API_EGL;
+constexpr int kTestApiInvalid = 0xDEADBEEF;
+constexpr int kTestProducerUsageBits = 0;
+constexpr bool kTestControlledByApp = true;
+
+// Builder pattern to slightly vary *almost* correct input
+// -- avoids copying and pasting
+struct QueueBufferInputBuilder {
+  IGraphicBufferProducer::QueueBufferInput build() {
+    return IGraphicBufferProducer::QueueBufferInput(
+        mTimestamp, mIsAutoTimestamp, mDataSpace, mCrop, mScalingMode,
+        mTransform, mFence);
+  }
+
+  QueueBufferInputBuilder& setTimestamp(int64_t timestamp) {
+    this->mTimestamp = timestamp;
+    return *this;
+  }
+
+  QueueBufferInputBuilder& setIsAutoTimestamp(bool isAutoTimestamp) {
+    this->mIsAutoTimestamp = isAutoTimestamp;
+    return *this;
+  }
+
+  QueueBufferInputBuilder& setDataSpace(android_dataspace dataSpace) {
+    this->mDataSpace = dataSpace;
+    return *this;
+  }
+
+  QueueBufferInputBuilder& setCrop(Rect crop) {
+    this->mCrop = crop;
+    return *this;
+  }
+
+  QueueBufferInputBuilder& setScalingMode(int scalingMode) {
+    this->mScalingMode = scalingMode;
+    return *this;
+  }
+
+  QueueBufferInputBuilder& setTransform(uint32_t transform) {
+    this->mTransform = transform;
+    return *this;
+  }
+
+  QueueBufferInputBuilder& setFence(sp<Fence> fence) {
+    this->mFence = fence;
+    return *this;
+  }
+
+ private:
+  int64_t mTimestamp{1384888611};
+  bool mIsAutoTimestamp{false};
+  android_dataspace mDataSpace{HAL_DATASPACE_UNKNOWN};
+  Rect mCrop{Rect(kDefaultWidth, kDefaultHeight)};
+  int mScalingMode{0};
+  uint32_t mTransform{0};
+  sp<Fence> mFence{Fence::NO_FENCE};
+};
+
+// This is a test that covers our implementation of bufferhubqueue-based
+// IGraphicBufferProducer.
+class BufferHubQueueProducerTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    const ::testing::TestInfo* const testInfo =
+        ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(),
+             testInfo->name());
+
+    auto core = BufferHubQueueCore::Create();
+    mProducer = new BufferHubQueueProducer(core);
+    ASSERT_TRUE(mProducer != nullptr);
+    mSurface = new Surface(mProducer, true);
+    ASSERT_TRUE(mSurface != nullptr);
+  }
+
+  // Connect to a producer in a 'correct' fashion.
+  void ConnectProducer() {
+    IGraphicBufferProducer::QueueBufferOutput output;
+    // Can connect the first time.
+    ASSERT_EQ(NO_ERROR, mProducer->connect(kDummyListener, kTestApi,
+                                           kTestControlledByApp, &output));
+  }
+
+  // Dequeue a buffer in a 'correct' fashion.
+  //   Precondition: Producer is connected.
+  void DequeueBuffer(int* outSlot) {
+    sp<Fence> fence;
+    ASSERT_NO_FATAL_FAILURE(DequeueBuffer(outSlot, &fence));
+  }
+
+  void DequeueBuffer(int* outSlot, sp<Fence>* outFence) {
+    ASSERT_NE(nullptr, outSlot);
+    ASSERT_NE(nullptr, outFence);
+
+    int ret = mProducer->dequeueBuffer(outSlot, outFence, kDefaultWidth,
+                                       kDefaultHeight, kDefaultFormat,
+                                       kTestProducerUsageBits, nullptr);
+    // BUFFER_NEEDS_REALLOCATION can be either on or off.
+    ASSERT_EQ(0, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & ret);
+
+    // Slot number should be in boundary.
+    ASSERT_LE(0, *outSlot);
+    ASSERT_GT(BufferQueueDefs::NUM_BUFFER_SLOTS, *outSlot);
+  }
+
+  // Create a generic "valid" input for queueBuffer
+  // -- uses the default buffer format, width, etc.
+  static IGraphicBufferProducer::QueueBufferInput CreateBufferInput() {
+    return QueueBufferInputBuilder().build();
+  }
+
+  const sp<IProducerListener> kDummyListener{new DummyProducerListener};
+
+  sp<BufferHubQueueProducer> mProducer;
+  sp<Surface> mSurface;
+};
+
+TEST_F(BufferHubQueueProducerTest, ConnectFirst_ReturnsError) {
+  IGraphicBufferProducer::QueueBufferOutput output;
+
+  // NULL output returns BAD_VALUE
+  EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApi,
+                                          kTestControlledByApp, nullptr));
+
+  // Invalid API returns bad value
+  EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApiInvalid,
+                                          kTestControlledByApp, &output));
+}
+
+TEST_F(BufferHubQueueProducerTest, ConnectAgain_ReturnsError) {
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+  // Can't connect when there is already a producer connected.
+  IGraphicBufferProducer::QueueBufferOutput output;
+  EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApi,
+                                          kTestControlledByApp, &output));
+}
+
+TEST_F(BufferHubQueueProducerTest, Disconnect_Succeeds) {
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+  ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
+}
+
+TEST_F(BufferHubQueueProducerTest, Disconnect_ReturnsError) {
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+  // Must disconnect with same API number
+  EXPECT_EQ(BAD_VALUE, mProducer->disconnect(kTestApiOther));
+  // API must not be out of range
+  EXPECT_EQ(BAD_VALUE, mProducer->disconnect(kTestApiInvalid));
+}
+
+TEST_F(BufferHubQueueProducerTest, Query_Succeeds) {
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+  int32_t value = -1;
+  EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_WIDTH, &value));
+  EXPECT_EQ(kDefaultWidth, static_cast<uint32_t>(value));
+
+  EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_HEIGHT, &value));
+  EXPECT_EQ(kDefaultHeight, static_cast<uint32_t>(value));
+
+  EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_FORMAT, &value));
+  EXPECT_EQ(kDefaultFormat, value);
+
+  EXPECT_EQ(NO_ERROR,
+            mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &value));
+  EXPECT_LE(0, value);
+  EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, static_cast<size_t>(value));
+
+  EXPECT_EQ(NO_ERROR,
+            mProducer->query(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value));
+  EXPECT_FALSE(value);  // Can't run behind when we haven't touched the queue
+
+  EXPECT_EQ(NO_ERROR,
+            mProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &value));
+  EXPECT_EQ(kDefaultConsumerUsageBits, value);
+}
+
+TEST_F(BufferHubQueueProducerTest, Query_ReturnsError) {
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+  // One past the end of the last 'query' enum value. Update this if we add more
+  // enums.
+  const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1;
+
+  int value;
+  // What was out of range
+  EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/ -1, &value));
+  EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/ 0xDEADBEEF, &value));
+  EXPECT_EQ(BAD_VALUE,
+            mProducer->query(NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE, &value));
+
+  // Some enums from window.h are 'invalid'
+  EXPECT_EQ(BAD_VALUE,
+            mProducer->query(NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &value));
+  EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_CONCRETE_TYPE, &value));
+  EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_WIDTH, &value));
+  EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_HEIGHT, &value));
+  EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_TRANSFORM_HINT, &value));
+
+  // Value was NULL
+  EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/ NULL));
+}
+
+TEST_F(BufferHubQueueProducerTest, Queue_Succeeds) {
+  int slot = -1;
+
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+
+  // Request the buffer (pre-requisite for queueing)
+  sp<GraphicBuffer> buffer;
+  ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+
+  // A generic "valid" input
+  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+  IGraphicBufferProducer::QueueBufferOutput output;
+
+  // Queue the buffer back into the BQ
+  ASSERT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output));
+
+  EXPECT_EQ(kDefaultWidth, output.width);
+  EXPECT_EQ(kDefaultHeight, output.height);
+  EXPECT_EQ(kDefaultTransformHint, output.transformHint);
+
+  // BufferHubQueue delivers buffers to consumer immediately.
+  EXPECT_EQ(0u, output.numPendingBuffers);
+
+  // Note that BufferHubQueue doesn't support nextFrameNumber as it seems to
+  // be a SurfaceFlinger specific optimization.
+  EXPECT_EQ(0u, output.nextFrameNumber);
+
+  // Buffer was not in the dequeued state
+  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
+}
+
+// Test invalid slot number
+TEST_F(BufferHubQueueProducerTest, QueueInvalidSlot_ReturnsError) {
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+  // A generic "valid" input
+  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+  IGraphicBufferProducer::QueueBufferOutput output;
+
+  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/ -1, input, &output));
+  EXPECT_EQ(BAD_VALUE,
+            mProducer->queueBuffer(/*slot*/ 0xDEADBEEF, input, &output));
+  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(BufferQueueDefs::NUM_BUFFER_SLOTS,
+                                              input, &output));
+}
+
+// Slot was not in the dequeued state (all slots start out in Free state)
+TEST_F(BufferHubQueueProducerTest, QueueNotDequeued_ReturnsError) {
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+  IGraphicBufferProducer::QueueBufferOutput output;
+
+  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/ 0, input, &output));
+}
+
+// Slot was enqueued without requesting a buffer
+TEST_F(BufferHubQueueProducerTest, QueueNotRequested_ReturnsError) {
+  int slot = -1;
+
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+
+  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+  IGraphicBufferProducer::QueueBufferOutput output;
+
+  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
+}
+
+// Test when fence was NULL
+TEST_F(BufferHubQueueProducerTest, QueueNoFence_ReturnsError) {
+  int slot = -1;
+
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+
+  sp<GraphicBuffer> buffer;
+  ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+
+  sp<Fence> nullFence = NULL;
+
+  IGraphicBufferProducer::QueueBufferInput input =
+      QueueBufferInputBuilder().setFence(nullFence).build();
+  IGraphicBufferProducer::QueueBufferOutput output;
+
+  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
+}
+
+// Test scaling mode was invalid
+TEST_F(BufferHubQueueProducerTest, QueueTestInvalidScalingMode_ReturnsError) {
+  int slot = -1;
+
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+
+  sp<GraphicBuffer> buffer;
+  ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+
+  IGraphicBufferProducer::QueueBufferInput input =
+      QueueBufferInputBuilder().setScalingMode(-1).build();
+  IGraphicBufferProducer::QueueBufferOutput output;
+
+  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
+
+  input = QueueBufferInputBuilder().setScalingMode(0xDEADBEEF).build();
+
+  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
+}
+
+// Test crop rect is out of bounds of the buffer dimensions
+TEST_F(BufferHubQueueProducerTest, QueueCropOutOfBounds_ReturnsError) {
+  int slot = -1;
+
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+
+  sp<GraphicBuffer> buffer;
+  ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+
+  IGraphicBufferProducer::QueueBufferInput input =
+      QueueBufferInputBuilder()
+          .setCrop(Rect(kDefaultWidth + 1, kDefaultHeight + 1))
+          .build();
+  IGraphicBufferProducer::QueueBufferOutput output;
+
+  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
+}
+
+TEST_F(BufferHubQueueProducerTest, CancelBuffer_Succeeds) {
+  int slot = -1;
+  sp<Fence> fence;
+
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot, &fence));
+
+  // Should be able to cancel buffer after a dequeue.
+  EXPECT_EQ(NO_ERROR, mProducer->cancelBuffer(slot, fence));
+}
+
+TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
+  return;
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+  int minUndequeuedBuffers;
+  ASSERT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                                       &minUndequeuedBuffers));
+
+  const int minBuffers = 1;
+  const int maxBuffers =
+      BufferQueueDefs::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
+
+  ASSERT_EQ(NO_ERROR, mProducer->setAsyncMode(false))
+      << "async mode: " << false;
+  ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(minBuffers))
+      << "bufferCount: " << minBuffers;
+
+  // Should now be able to dequeue up to minBuffers times
+  // Should now be able to dequeue up to maxBuffers times
+  int slot = -1;
+  for (int i = 0; i < minBuffers; ++i) {
+    ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+  }
+
+  ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxBuffers));
+
+  // queue the first buffer to enable max dequeued buffer count checking
+  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+  IGraphicBufferProducer::QueueBufferOutput output;
+  sp<GraphicBuffer> buffer;
+  ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+  ASSERT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output));
+
+  sp<Fence> fence;
+  for (int i = 0; i < maxBuffers; ++i) {
+    ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot, &fence));
+  }
+
+  // Cancel a buffer, so we can decrease the buffer count
+  ASSERT_EQ(NO_ERROR, mProducer->cancelBuffer(slot, fence));
+
+  // Should now be able to decrease the max dequeued count by 1
+  ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxBuffers - 1));
+}
+
+TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Fails) {
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+
+  int minUndequeuedBuffers;
+  ASSERT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                                       &minUndequeuedBuffers));
+
+  const int minBuffers = 1;
+  const int maxBuffers =
+      BufferQueueDefs::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
+
+  ASSERT_EQ(NO_ERROR, mProducer->setAsyncMode(false))
+      << "async mode: " << false;
+  // Buffer count was out of range
+  EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(0))
+      << "bufferCount: " << 0;
+  EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1))
+      << "bufferCount: " << maxBuffers + 1;
+
+  // Set max dequeue count to 2
+  ASSERT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(2));
+  // Dequeue 2 buffers
+  int slot = -1;
+  sp<Fence> fence;
+  for (int i = 0; i < 2; i++) {
+    ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                      (mProducer->dequeueBuffer(
+                          &slot, &fence, kDefaultWidth, kDefaultHeight,
+                          kDefaultFormat, kTestProducerUsageBits, nullptr)))
+        << "slot: " << slot;
+  }
+
+  // Client has too many buffers dequeued
+  EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(1))
+      << "bufferCount: " << minBuffers;
+}
+
+TEST_F(BufferHubQueueProducerTest,
+       DisconnectedProducerReturnsError_dequeueBuffer) {
+  int slot = -1;
+  sp<Fence> fence;
+
+  ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth,
+                                              kDefaultHeight, kDefaultFormat,
+                                              kTestProducerUsageBits, nullptr));
+}
+
+TEST_F(BufferHubQueueProducerTest,
+       DisconnectedProducerReturnsError_requestBuffer) {
+  int slot = -1;
+  sp<GraphicBuffer> buffer;
+
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+
+  // Shouldn't be able to request buffer after disconnect.
+  ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
+  ASSERT_EQ(NO_INIT, mProducer->requestBuffer(slot, &buffer));
+}
+
+TEST_F(BufferHubQueueProducerTest,
+       DisconnectedProducerReturnsError_queueBuffer) {
+  int slot = -1;
+  sp<GraphicBuffer> buffer;
+
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+  ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+
+  // A generic "valid" input
+  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+  IGraphicBufferProducer::QueueBufferOutput output;
+
+  // Shouldn't be able to queue buffer after disconnect.
+  ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
+  ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output));
+}
+
+TEST_F(BufferHubQueueProducerTest,
+       DisconnectedProducerReturnsError_cancelBuffer) {
+  int slot = -1;
+  sp<GraphicBuffer> buffer;
+
+  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
+  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+  ASSERT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+
+  // Shouldn't be able to cancel buffer after disconnect.
+  ASSERT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
+  ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, Fence::NO_FENCE));
 }
 
 }  // namespace
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 9952e59..6d39cdb 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -160,8 +160,7 @@
       return nullptr;
     }
 
-    producer_queue_ =
-        ProducerQueue::Import<DisplaySurfaceMetadata>(status.take());
+    producer_queue_ = ProducerQueue::Import(status.take());
   }
   return producer_queue_;
 }
diff --git a/libs/vr/libdisplay/video_mesh_surface_client.cpp b/libs/vr/libdisplay/video_mesh_surface_client.cpp
index 04cc194..a2307e5 100644
--- a/libs/vr/libdisplay/video_mesh_surface_client.cpp
+++ b/libs/vr/libdisplay/video_mesh_surface_client.cpp
@@ -30,8 +30,7 @@
       return nullptr;
     }
 
-    producer_queue_ =
-        ProducerQueue::Import<VideoMeshSurfaceBufferMetadata>(status.take());
+    producer_queue_ = ProducerQueue::Import(status.take());
   }
   return producer_queue_;
 }
diff --git a/libs/vr/libdvr/Android.mk b/libs/vr/libdvr/Android.mk
index 5449cb5..1050283 100644
--- a/libs/vr/libdvr/Android.mk
+++ b/libs/vr/libdvr/Android.mk
@@ -33,6 +33,7 @@
     dvr_api.cpp \
     dvr_buffer.cpp \
     dvr_buffer_queue.cpp \
+    dvr_hardware_composer_client.cpp \
     dvr_surface.cpp \
     vsync_client_api.cpp \
 
@@ -42,12 +43,14 @@
     libdisplay \
     libvrsensor \
     libvirtualtouchpadclient \
+    libvr_hwc-impl \
+    libvr_hwc-binder \
 
 LOCAL_SHARED_LIBRARIES := \
     android.hardware.graphics.bufferqueue@1.0 \
     android.hidl.token@1.0-utils \
-    libandroid_runtime \
     libbase \
+    libnativewindow \
 
 include $(BUILD_STATIC_LIBRARY)
 
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index f464411..49702fd 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -11,6 +11,7 @@
 
 // Headers not yet moved into libdvr.
 // TODO(jwcai) Move these once their callers are moved into Google3.
+#include <dvr/dvr_hardware_composer_client.h>
 #include <dvr/pose_client.h>
 #include <dvr/virtual_touchpad_client.h>
 
@@ -100,6 +101,27 @@
     dvr_api->virtual_touchpad_touch = dvrVirtualTouchpadTouch;
     dvr_api->virtual_touchpad_button_state = dvrVirtualTouchpadButtonState;
 
+    // dvr_hardware_composer_client.h
+    dvr_api->hwc_client_create = dvrHwcClientCreate;
+    dvr_api->hwc_client_destroy = dvrHwcClientDestroy;
+    dvr_api->hwc_frame_destroy = dvrHwcFrameDestroy;
+    dvr_api->hwc_frame_get_display_id = dvrHwcFrameGetDisplayId;
+    dvr_api->hwc_frame_get_display_width = dvrHwcFrameGetDisplayWidth;
+    dvr_api->hwc_frame_get_display_height = dvrHwcFrameGetDisplayHeight;
+    dvr_api->hwc_frame_get_display_removed = dvrHwcFrameGetDisplayRemoved;
+    dvr_api->hwc_frame_get_layer_count = dvrHwcFrameGetLayerCount;
+    dvr_api->hwc_frame_get_layer_id = dvrHwcFrameGetLayerId;
+    dvr_api->hwc_frame_get_layer_buffer = dvrHwcFrameGetLayerBuffer;
+    dvr_api->hwc_frame_get_layer_fence = dvrHwcFrameGetLayerFence;
+    dvr_api->hwc_frame_get_layer_display_frame =
+        dvrHwcFrameGetLayerDisplayFrame;
+    dvr_api->hwc_frame_get_layer_crop = dvrHwcFrameGetLayerCrop;
+    dvr_api->hwc_frame_get_layer_blend_mode = dvrHwcFrameGetLayerBlendMode;
+    dvr_api->hwc_frame_get_layer_alpha = dvrHwcFrameGetLayerAlpha;
+    dvr_api->hwc_frame_get_layer_type = dvrHwcFrameGetLayerType;
+    dvr_api->hwc_frame_get_layer_application_id =
+        dvrHwcFrameGetLayerApplicationId;
+
     return 0;
   }
   return -EINVAL;
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 4ce0b22..dfde21d 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -1,11 +1,10 @@
 #include "include/dvr/dvr_buffer_queue.h"
 
+#include <android/native_window.h>
 #include <gui/Surface.h>
 #include <private/dvr/buffer_hub_queue_client.h>
 #include <private/dvr/buffer_hub_queue_producer.h>
 
-#include <android_runtime/android_view_Surface.h>
-
 #define CHECK_PARAM(param)                                               \
   LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \
                       __FUNCTION__)
@@ -15,6 +14,9 @@
 extern "C" {
 
 void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
+  if (write_queue != nullptr && write_queue->native_window_ != nullptr) {
+    ANativeWindow_release(write_queue->native_window_);
+  }
   delete write_queue;
 }
 
@@ -23,16 +25,30 @@
   return write_queue->producer_queue_->capacity();
 }
 
-jobject dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
-                                              JNIEnv* env) {
-  CHECK_PARAM(env);
+int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
+                                          ANativeWindow** out_window) {
   CHECK_PARAM(write_queue);
+  CHECK_PARAM(out_window);
 
-  std::shared_ptr<dvr::BufferHubQueueCore> core =
-      dvr::BufferHubQueueCore::Create(write_queue->producer_queue_);
+  // Lazy creation of |native_window_|.
+  if (write_queue->native_window_ == nullptr) {
+    std::shared_ptr<dvr::BufferHubQueueCore> core =
+        dvr::BufferHubQueueCore::Create(write_queue->producer_queue_);
+    if (core == nullptr) {
+      ALOGE(
+          "dvrWriteBufferQueueGetExternalSurface: Failed to create native "
+          "window.");
+      return -ENOMEM;
+    }
 
-  return android_view_Surface_createFromIGraphicBufferProducer(
-      env, new dvr::BufferHubQueueProducer(core));
+    sp<IGraphicBufferProducer> gbp = new dvr::BufferHubQueueProducer(core);
+    sp<Surface> surface = new Surface(gbp, true);
+    write_queue->native_window_ = static_cast<ANativeWindow*>(surface.get());
+    ANativeWindow_acquire(write_queue->native_window_);
+  }
+
+  *out_window = write_queue->native_window_;
+  return 0;
 }
 
 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
diff --git a/services/vr/hardware_composer/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
similarity index 79%
rename from services/vr/hardware_composer/dvr_hardware_composer_client.cpp
rename to libs/vr/libdvr/dvr_hardware_composer_client.cpp
index 39fa9fc..e5665e1 100644
--- a/services/vr/hardware_composer/dvr_hardware_composer_client.cpp
+++ b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
@@ -1,7 +1,8 @@
-#include "private/android/dvr_hardware_composer_client.h"
+#include "include/dvr/dvr_hardware_composer_client.h"
 
 #include <android/dvr/IVrComposer.h>
 #include <android/dvr/BnVrComposerCallback.h>
+#include <android/hardware_buffer.h>
 #include <binder/IServiceManager.h>
 #include <private/android/AHardwareBufferHelpers.h>
 
@@ -15,7 +16,8 @@
 
 class HwcCallback : public android::dvr::BnVrComposerCallback {
  public:
-  explicit HwcCallback(DvrHwcOnFrameCallback callback);
+  explicit HwcCallback(DvrHwcOnFrameCallback callback,
+                       void* client_state);
   ~HwcCallback() override;
 
   std::unique_ptr<DvrHwcFrame> DequeueFrame();
@@ -27,13 +29,14 @@
       android::dvr::ParcelableUniqueFd* fence) override;
 
   DvrHwcOnFrameCallback callback_;
+  void* client_state_;
 
   HwcCallback(const HwcCallback&) = delete;
   void operator=(const HwcCallback&) = delete;
 };
 
-HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback)
-    : callback_(callback) {}
+HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback, void* client_state)
+    : callback_(callback), client_state_(client_state) {}
 
 HwcCallback::~HwcCallback() {}
 
@@ -43,7 +46,8 @@
   std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
   dvr_frame->frame = frame.frame();
 
-  fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
+  fence->set_fence(android::base::unique_fd(callback_(client_state_,
+                                                      dvr_frame.release())));
   return android::binder::Status::ok();
 }
 
@@ -54,7 +58,7 @@
   android::sp<HwcCallback> callback;
 };
 
-DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback) {
+DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback, void* data) {
   std::unique_ptr<DvrHwcClient> client(new DvrHwcClient());
 
   android::sp<android::IServiceManager> sm(android::defaultServiceManager());
@@ -63,7 +67,7 @@
   if (!client->composer.get())
     return nullptr;
 
-  client->callback = new HwcCallback(callback);
+  client->callback = new HwcCallback(callback, data);
   android::binder::Status status = client->composer->registerObserver(
       client->callback);
   if (!status.isOk())
@@ -72,6 +76,10 @@
   return client.release();
 }
 
+void dvrHwcClientDestroy(DvrHwcClient* client) {
+  delete client;
+}
+
 void dvrHwcFrameDestroy(DvrHwcFrame* frame) {
   delete frame;
 }
@@ -80,6 +88,18 @@
   return frame->frame.display_id;
 }
 
+int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame) {
+  return frame->frame.display_width;
+}
+
+int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame) {
+  return frame->frame.display_height;
+}
+
+bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame) {
+  return frame->frame.removed;
+}
+
 size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame) {
   return frame->frame.layers.size();
 }
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index d840b6c..a4fef19 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -5,12 +5,14 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <jni.h>
+#include <dvr/dvr_hardware_composer_defs.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+typedef struct ANativeWindow ANativeWindow;
+
 typedef struct DvrPoseAsync DvrPoseAsync;
 
 typedef struct DvrDisplayManagerClient DvrDisplayManagerClient;
@@ -88,8 +90,8 @@
 typedef void (*DvrWriteBufferQueueDestroyPtr)(DvrWriteBufferQueue* write_queue);
 typedef size_t (*DvrWriteBufferQueueGetCapacityPtr)(
     DvrWriteBufferQueue* write_queue);
-typedef jobject (*DvrWriteBufferQueueGetExternalSurfacePtr)(
-    DvrWriteBufferQueue* write_queue, JNIEnv* env);
+typedef int (*DvrWriteBufferQueueGetExternalSurfacePtr)(
+    DvrWriteBufferQueue* write_queue, ANativeWindow** out_window);
 typedef int (*DvrWriteBufferQueueCreateReadQueuePtr)(
     DvrWriteBufferQueue* write_queue, DvrReadBufferQueue** out_read_queue);
 typedef int (*DvrWriteBufferQueueDequeuePtr)(DvrWriteBufferQueue* write_queue,
@@ -144,6 +146,37 @@
 typedef int (*DvrVirtualTouchpadButtonStatePtr)(DvrVirtualTouchpad* client,
                                                 int touchpad, int buttons);
 
+// dvr_hardware_composer_client.h
+typedef struct DvrHwcClient DvrHwcClient;
+typedef struct DvrHwcFrame DvrHwcFrame;
+typedef int(*DvrHwcOnFrameCallback)(void* client_state, DvrHwcFrame* frame);
+typedef DvrHwcClient* (*DvrHwcClientCreatePtr)(DvrHwcOnFrameCallback callback,
+                                               void* client_state);
+typedef void (*DvrHwcClientDestroyPtr)(DvrHwcClient* client);
+typedef void (*DvrHwcFrameDestroyPtr)(DvrHwcFrame* frame);
+typedef Display (*DvrHwcFrameGetDisplayIdPtr)(DvrHwcFrame* frame);
+typedef int32_t (*DvrHwcFrameGetDisplayWidthPtr)(DvrHwcFrame* frame);
+typedef int32_t (*DvrHwcFrameGetDisplayHeightPtr)(DvrHwcFrame* frame);
+typedef bool (*DvrHwcFrameGetDisplayRemovedPtr)(DvrHwcFrame* frame);
+typedef size_t (*DvrHwcFrameGetLayerCountPtr)(DvrHwcFrame* frame);
+typedef Layer (*DvrHwcFrameGetLayerIdPtr)(DvrHwcFrame* frame, size_t layer_index);
+typedef AHardwareBuffer* (*DvrHwcFrameGetLayerBufferPtr)(DvrHwcFrame* frame,
+                                                         size_t layer_index);
+typedef int (*DvrHwcFrameGetLayerFencePtr)(DvrHwcFrame* frame,
+                                           size_t layer_index);
+typedef Recti (*DvrHwcFrameGetLayerDisplayFramePtr)(DvrHwcFrame* frame,
+                                                    size_t layer_index);
+typedef Rectf (*DvrHwcFrameGetLayerCropPtr)(DvrHwcFrame* frame,
+                                            size_t layer_index);
+typedef BlendMode (*DvrHwcFrameGetLayerBlendModePtr)(DvrHwcFrame* frame,
+                                                     size_t layer_index);
+typedef float (*DvrHwcFrameGetLayerAlphaPtr)(DvrHwcFrame* frame,
+                                             size_t layer_index);
+typedef uint32_t (*DvrHwcFrameGetLayerTypePtr)(DvrHwcFrame* frame,
+                                               size_t layer_index);
+typedef uint32_t (*DvrHwcFrameGetLayerApplicationIdPtr)(DvrHwcFrame* frame,
+                                                        size_t layer_index);
+
 struct DvrApi_v1 {
   // Display manager client
   DvrDisplayManagerClientCreatePtr display_manager_client_create;
@@ -220,6 +253,25 @@
   DvrVirtualTouchpadDetachPtr virtual_touchpad_detach;
   DvrVirtualTouchpadTouchPtr virtual_touchpad_touch;
   DvrVirtualTouchpadButtonStatePtr virtual_touchpad_button_state;
+
+  // VR HWComposer client
+  DvrHwcClientCreatePtr hwc_client_create;
+  DvrHwcClientDestroyPtr hwc_client_destroy;
+  DvrHwcFrameDestroyPtr hwc_frame_destroy;
+  DvrHwcFrameGetDisplayIdPtr hwc_frame_get_display_id;
+  DvrHwcFrameGetDisplayWidthPtr hwc_frame_get_display_width;
+  DvrHwcFrameGetDisplayHeightPtr hwc_frame_get_display_height;
+  DvrHwcFrameGetDisplayRemovedPtr hwc_frame_get_display_removed;
+  DvrHwcFrameGetLayerCountPtr hwc_frame_get_layer_count;
+  DvrHwcFrameGetLayerIdPtr hwc_frame_get_layer_id;
+  DvrHwcFrameGetLayerBufferPtr hwc_frame_get_layer_buffer;
+  DvrHwcFrameGetLayerFencePtr hwc_frame_get_layer_fence;
+  DvrHwcFrameGetLayerDisplayFramePtr hwc_frame_get_layer_display_frame;
+  DvrHwcFrameGetLayerCropPtr hwc_frame_get_layer_crop;
+  DvrHwcFrameGetLayerBlendModePtr hwc_frame_get_layer_blend_mode;
+  DvrHwcFrameGetLayerAlphaPtr hwc_frame_get_layer_alpha;
+  DvrHwcFrameGetLayerTypePtr hwc_frame_get_layer_type;
+  DvrHwcFrameGetLayerApplicationIdPtr hwc_frame_get_layer_application_id;
 };
 
 int dvrGetApi(void* api, size_t struct_size, int version);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index 80c9779..ba39513 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -2,12 +2,13 @@
 #define ANDROID_DVR_BUFFER_QUEUE_H_
 
 #include <dvr/dvr_buffer.h>
-#include <jni.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+typedef struct ANativeWindow ANativeWindow;
+
 typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
 typedef struct DvrReadBufferQueue DvrReadBufferQueue;
 
@@ -15,10 +16,12 @@
 void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue);
 size_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue);
 
-// Returns ANativeWindow in the form of jobject. Can be casted to ANativeWindow
-// using ANativeWindow_fromSurface NDK API.
-jobject dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
-                                              JNIEnv* env);
+// Returns ANativeWindow. Can be casted to a Java Surface using
+// ANativeWindow_toSurface NDK API. Note that this method does not acquire an
+// additional reference to the ANativeWindow returned, don't call
+// ANativeWindow_release on it.
+int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
+                                          ANativeWindow** out_window);
 
 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
                                        DvrReadBufferQueue** out_read_queue);
diff --git a/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
similarity index 61%
rename from services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h
rename to libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
index 063c16d..692864d 100644
--- a/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
@@ -1,29 +1,45 @@
-#ifndef VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
-#define VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
 
-#include <android/dvr_hardware_composer_defs.h>
-#include <android/hardware_buffer.h>
+#include <dvr/dvr_hardware_composer_defs.h>
+#include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+typedef struct AHardwareBuffer AHardwareBuffer;
 typedef struct DvrHwcClient DvrHwcClient;
 typedef struct DvrHwcFrame DvrHwcFrame;
 
 // Called when a new frame has arrived.
 //
+// @param client_state Pointer to client state passed in |dvrHwcCreateClient()|.
 // @param frame New frame. Owned by the client.
 // @return fence FD for the release of the last frame.
-typedef int(*DvrHwcOnFrameCallback)(DvrHwcFrame* frame);
+typedef int(*DvrHwcOnFrameCallback)(void* client_state, DvrHwcFrame* frame);
 
-DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback);
+// @param callback Called when a new frame is available.
+// @param client_state Pointer to client state passed back in the callback.
+DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback,
+                                 void* client_state);
+
+void dvrHwcClientDestroy(DvrHwcClient* client);
 
 // Called to free the frame information.
 void dvrHwcFrameDestroy(DvrHwcFrame* frame);
 
 Display dvrHwcFrameGetDisplayId(DvrHwcFrame* frame);
 
+int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame);
+
+int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame);
+
+// @return True if the display has been removed. In this case the current frame
+// does not contain any valid layers to display. It is a signal to clean up any
+// display related state.
+bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame);
+
 // @return Number of layers in the frame.
 size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame);
 
@@ -59,4 +75,4 @@
 }  // extern "C"
 #endif
 
-#endif  // VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
diff --git a/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
similarity index 78%
rename from services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h
rename to libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
index 3186f82..546ed7b 100644
--- a/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
@@ -1,5 +1,5 @@
-#ifndef VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
-#define VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
+#ifndef ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
+#define ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
 
 #include <inttypes.h>
 
@@ -47,4 +47,4 @@
 }  // extern "C"
 #endif
 
-#endif  // VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_DEFS_H
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_DEFS_H
diff --git a/libs/vr/libdvr/tests/Android.mk b/libs/vr/libdvr/tests/Android.mk
index 158d58f..75e2a7d 100644
--- a/libs/vr/libdvr/tests/Android.mk
+++ b/libs/vr/libdvr/tests/Android.mk
@@ -9,6 +9,7 @@
     libhardware \
     libui \
     libutils \
+    libnativewindow \
 
 static_libraries := \
     libdvr \
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index f344a24..1c9eadd 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -1,4 +1,5 @@
 #include <dvr/dvr_buffer_queue.h>
+#include <gui/Surface.h>
 #include <private/dvr/buffer_hub_queue_client.h>
 
 #include <base/logging.h>
@@ -143,6 +144,17 @@
   dvrReadBufferQueueDestroy(read_queue);
 }
 
+TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
+  ANativeWindow* window = nullptr;
+  int ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
+
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, window);
+
+  sp<Surface> surface = static_cast<Surface*>(window);
+  ASSERT_TRUE(Surface::isValid(surface));
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libpdx/client.cpp b/libs/vr/libpdx/client.cpp
index c318628..bfa2d87 100644
--- a/libs/vr/libpdx/client.cpp
+++ b/libs/vr/libpdx/client.cpp
@@ -4,7 +4,6 @@
 #include <log/log.h>
 
 #include <pdx/trace.h>
-#include "errno_guard.h"
 
 namespace android {
 namespace pdx {
@@ -84,7 +83,6 @@
 
 Status<void> Client::SendImpulse(int opcode) {
   PDX_TRACE_NAME("Client::SendImpulse");
-  ErrnoGuard errno_guard;
 
   auto status = CheckReconnect();
   if (!status)
@@ -98,7 +96,6 @@
 Status<void> Client::SendImpulse(int opcode, const void* buffer,
                                  size_t length) {
   PDX_TRACE_NAME("Client::SendImpulse");
-  ErrnoGuard errno_guard;
 
   auto status = CheckReconnect();
   if (!status)
@@ -110,7 +107,6 @@
 }
 
 void Client::Close(int error) {
-  ErrnoGuard errno_guard;
   channel_.reset();
   // Normalize error codes to negative integer space.
   error_ = error <= 0 ? error : -error;
@@ -228,37 +224,38 @@
   CheckDisconnect(*ret);
 }
 
-FileReference Transaction::PushFileHandle(const LocalHandle& handle) {
-  return client_.CheckReconnect() && EnsureStateAllocated()
-             ? client_.GetChannel()->PushFileHandle(state_, handle)
-             : -1;
+Status<FileReference> Transaction::PushFileHandle(const LocalHandle& handle) {
+  if (client_.CheckReconnect() && EnsureStateAllocated())
+    return client_.GetChannel()->PushFileHandle(state_, handle);
+  return ErrorStatus{ESHUTDOWN};
 }
 
-FileReference Transaction::PushFileHandle(const BorrowedHandle& handle) {
-  return client_.CheckReconnect() && EnsureStateAllocated()
-             ? client_.GetChannel()->PushFileHandle(state_, handle)
-             : -1;
+Status<FileReference> Transaction::PushFileHandle(
+    const BorrowedHandle& handle) {
+  if (client_.CheckReconnect() && EnsureStateAllocated())
+    return client_.GetChannel()->PushFileHandle(state_, handle);
+  return ErrorStatus{ESHUTDOWN};
 }
 
-FileReference Transaction::PushFileHandle(const RemoteHandle& handle) {
+Status<FileReference> Transaction::PushFileHandle(const RemoteHandle& handle) {
   return handle.Get();
 }
 
-ChannelReference Transaction::PushChannelHandle(
+Status<ChannelReference> Transaction::PushChannelHandle(
     const LocalChannelHandle& handle) {
-  return client_.CheckReconnect() && EnsureStateAllocated()
-             ? client_.GetChannel()->PushChannelHandle(state_, handle)
-             : -1;
+  if (client_.CheckReconnect() && EnsureStateAllocated())
+    return client_.GetChannel()->PushChannelHandle(state_, handle);
+  return ErrorStatus{ESHUTDOWN};
 }
 
-ChannelReference Transaction::PushChannelHandle(
+Status<ChannelReference> Transaction::PushChannelHandle(
     const BorrowedChannelHandle& handle) {
-  return client_.CheckReconnect() && EnsureStateAllocated()
-             ? client_.GetChannel()->PushChannelHandle(state_, handle)
-             : -1;
+  if (client_.CheckReconnect() && EnsureStateAllocated())
+    return client_.GetChannel()->PushChannelHandle(state_, handle);
+  return ErrorStatus{ESHUTDOWN};
 }
 
-ChannelReference Transaction::PushChannelHandle(
+Status<ChannelReference> Transaction::PushChannelHandle(
     const RemoteChannelHandle& handle) {
   return handle.value();
 }
diff --git a/libs/vr/libpdx/client_tests.cpp b/libs/vr/libpdx/client_tests.cpp
index f1fb6d1..99ccc69 100644
--- a/libs/vr/libpdx/client_tests.cpp
+++ b/libs/vr/libpdx/client_tests.cpp
@@ -518,28 +518,29 @@
   EXPECT_CALL(*mock_channel(),
               PushFileHandle(kTransactionState, A<const LocalHandle&>()))
       .WillOnce(Return(1));
-  EXPECT_EQ(1, transaction_.PushFileHandle(LocalHandle{-1}));
+  EXPECT_EQ(1, transaction_.PushFileHandle(LocalHandle{-1}).get());
 
   EXPECT_CALL(*mock_channel(),
               PushFileHandle(kTransactionState, A<const BorrowedHandle&>()))
       .WillOnce(Return(2));
-  EXPECT_EQ(2, transaction_.PushFileHandle(BorrowedHandle{-1}));
+  EXPECT_EQ(2, transaction_.PushFileHandle(BorrowedHandle{-1}).get());
 
-  EXPECT_EQ(3, transaction_.PushFileHandle(RemoteHandle{3}));
+  EXPECT_EQ(3, transaction_.PushFileHandle(RemoteHandle{3}).get());
 
   EXPECT_CALL(
       *mock_channel(),
       PushChannelHandle(kTransactionState, A<const LocalChannelHandle&>()))
       .WillOnce(Return(11));
-  EXPECT_EQ(11, transaction_.PushChannelHandle(LocalChannelHandle{nullptr, 1}));
+  EXPECT_EQ(
+      11, transaction_.PushChannelHandle(LocalChannelHandle{nullptr, 1}).get());
 
   EXPECT_CALL(
       *mock_channel(),
       PushChannelHandle(kTransactionState, A<const BorrowedChannelHandle&>()))
       .WillOnce(Return(12));
-  EXPECT_EQ(12, transaction_.PushChannelHandle(BorrowedChannelHandle{2}));
+  EXPECT_EQ(12, transaction_.PushChannelHandle(BorrowedChannelHandle{2}).get());
 
-  EXPECT_EQ(13, transaction_.PushChannelHandle(RemoteChannelHandle{13}));
+  EXPECT_EQ(13, transaction_.PushChannelHandle(RemoteChannelHandle{13}).get());
 }
 
 TEST_F(ClientTransactionTest, GetHandle) {
diff --git a/libs/vr/libpdx/errno_guard.h b/libs/vr/libpdx/errno_guard.h
deleted file mode 100644
index fc7dfdf..0000000
--- a/libs/vr/libpdx/errno_guard.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef ANDROID_PDX_ERRNO_GUARD_H_
-#define ANDROID_PDX_ERRNO_GUARD_H_
-
-#include <errno.h>
-
-namespace android {
-namespace pdx {
-
-// Automatically saves and restores the system errno for API implementations to
-// prevent internal use errno from affecting API callers.
-class ErrnoGuard {
- public:
-  ErrnoGuard() : saved_errno_(errno) {}
-  ~ErrnoGuard() { errno = saved_errno_; }
-
-  int saved_errno() const { return saved_errno_; }
-
- private:
-  int saved_errno_;
-
-  ErrnoGuard(const ErrnoGuard&) = delete;
-  void operator=(const ErrnoGuard&) = delete;
-};
-
-// Checks |return_code| and returns either it or the negated system errno based
-// on the return code value.
-inline int ReturnCodeOrError(int return_code) {
-  return return_code < 0 ? -errno : return_code;
-}
-
-}  // namespace pdx
-}  // namespace android
-
-#endif  // ANDROID_PDX_ERRNO_GUARD_H_
diff --git a/libs/vr/libpdx/private/pdx/client.h b/libs/vr/libpdx/private/pdx/client.h
index a590087..656de7e 100644
--- a/libs/vr/libpdx/private/pdx/client.h
+++ b/libs/vr/libpdx/private/pdx/client.h
@@ -253,13 +253,14 @@
   }
 
   // OutputResourceMapper
-  FileReference PushFileHandle(const LocalHandle& handle) override;
-  FileReference PushFileHandle(const BorrowedHandle& handle) override;
-  FileReference PushFileHandle(const RemoteHandle& handle) override;
-  ChannelReference PushChannelHandle(const LocalChannelHandle& handle) override;
-  ChannelReference PushChannelHandle(
+  Status<FileReference> PushFileHandle(const LocalHandle& handle) override;
+  Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override;
+  Status<FileReference> PushFileHandle(const RemoteHandle& handle) override;
+  Status<ChannelReference> PushChannelHandle(
+      const LocalChannelHandle& handle) override;
+  Status<ChannelReference> PushChannelHandle(
       const BorrowedChannelHandle& handle) override;
-  ChannelReference PushChannelHandle(
+  Status<ChannelReference> PushChannelHandle(
       const RemoteChannelHandle& handle) override;
 
   // InputResourceMapper
diff --git a/libs/vr/libpdx/private/pdx/message_writer.h b/libs/vr/libpdx/private/pdx/message_writer.h
index 0cb6e40..4a101d6 100644
--- a/libs/vr/libpdx/private/pdx/message_writer.h
+++ b/libs/vr/libpdx/private/pdx/message_writer.h
@@ -3,20 +3,22 @@
 
 #include <pdx/channel_handle.h>
 #include <pdx/file_handle.h>
+#include <pdx/status.h>
 
 namespace android {
 namespace pdx {
 
 class OutputResourceMapper {
  public:
-  virtual FileReference PushFileHandle(const LocalHandle& handle) = 0;
-  virtual FileReference PushFileHandle(const BorrowedHandle& handle) = 0;
-  virtual FileReference PushFileHandle(const RemoteHandle& handle) = 0;
-  virtual ChannelReference PushChannelHandle(
+  virtual Status<FileReference> PushFileHandle(const LocalHandle& handle) = 0;
+  virtual Status<FileReference> PushFileHandle(
+      const BorrowedHandle& handle) = 0;
+  virtual Status<FileReference> PushFileHandle(const RemoteHandle& handle) = 0;
+  virtual Status<ChannelReference> PushChannelHandle(
       const LocalChannelHandle& handle) = 0;
-  virtual ChannelReference PushChannelHandle(
+  virtual Status<ChannelReference> PushChannelHandle(
       const BorrowedChannelHandle& handle) = 0;
-  virtual ChannelReference PushChannelHandle(
+  virtual Status<ChannelReference> PushChannelHandle(
       const RemoteChannelHandle& handle) = 0;
 
  protected:
diff --git a/libs/vr/libpdx/private/pdx/mock_message_writer.h b/libs/vr/libpdx/private/pdx/mock_message_writer.h
index 3c513d7..e06e5bb 100644
--- a/libs/vr/libpdx/private/pdx/mock_message_writer.h
+++ b/libs/vr/libpdx/private/pdx/mock_message_writer.h
@@ -9,15 +9,18 @@
 
 class MockOutputResourceMapper : public OutputResourceMapper {
  public:
-  MOCK_METHOD1(PushFileHandle, FileReference(const LocalHandle& handle));
-  MOCK_METHOD1(PushFileHandle, FileReference(const BorrowedHandle& handle));
-  MOCK_METHOD1(PushFileHandle, FileReference(const RemoteHandle& handle));
+  MOCK_METHOD1(PushFileHandle,
+               Status<FileReference>(const LocalHandle& handle));
+  MOCK_METHOD1(PushFileHandle,
+               Status<FileReference>(const BorrowedHandle& handle));
+  MOCK_METHOD1(PushFileHandle,
+               Status<FileReference>(const RemoteHandle& handle));
   MOCK_METHOD1(PushChannelHandle,
-               ChannelReference(const LocalChannelHandle& handle));
+               Status<ChannelReference>(const LocalChannelHandle& handle));
   MOCK_METHOD1(PushChannelHandle,
-               ChannelReference(const BorrowedChannelHandle& handle));
+               Status<ChannelReference>(const BorrowedChannelHandle& handle));
   MOCK_METHOD1(PushChannelHandle,
-               ChannelReference(const RemoteChannelHandle& handle));
+               Status<ChannelReference>(const RemoteChannelHandle& handle));
 };
 
 class MockMessageWriter : public MessageWriter {
diff --git a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
index ead74d5..e741d4a 100644
--- a/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
+++ b/libs/vr/libpdx/private/pdx/mock_service_endpoint.h
@@ -10,46 +10,54 @@
 class MockEndpoint : public Endpoint {
  public:
   MOCK_CONST_METHOD0(GetIpcTag, uint32_t());
-  MOCK_METHOD1(SetService, int(Service* service));
-  MOCK_METHOD2(SetChannel, int(int channel_id, Channel* channel));
-  MOCK_METHOD1(CloseChannel, int(int channel_id));
+  MOCK_METHOD1(SetService, Status<void>(Service* service));
+  MOCK_METHOD2(SetChannel, Status<void>(int channel_id, Channel* channel));
+  MOCK_METHOD1(CloseChannel, Status<void>(int channel_id));
   MOCK_METHOD3(ModifyChannelEvents,
-               int(int channel_id, int clear_mask, int set_mask));
+               Status<void>(int channel_id, int clear_mask, int set_mask));
   MOCK_METHOD4(PushChannel,
                Status<RemoteChannelHandle>(Message* message, int flags,
                                            Channel* channel, int* channel_id));
   MOCK_METHOD3(CheckChannel,
                Status<int>(const Message* message, ChannelReference ref,
                            Channel** channel));
-  MOCK_METHOD1(DefaultHandleMessage, int(const MessageInfo& info));
-  MOCK_METHOD1(MessageReceive, int(Message* message));
-  MOCK_METHOD2(MessageReply, int(Message* message, int return_code));
-  MOCK_METHOD2(MessageReplyFd, int(Message* message, unsigned int push_fd));
+  MOCK_METHOD1(MessageReceive, Status<void>(Message* message));
+  MOCK_METHOD2(MessageReply, Status<void>(Message* message, int return_code));
+  MOCK_METHOD2(MessageReplyFd,
+               Status<void>(Message* message, unsigned int push_fd));
   MOCK_METHOD2(MessageReplyChannelHandle,
-               int(Message* message, const LocalChannelHandle& handle));
+               Status<void>(Message* message,
+                            const LocalChannelHandle& handle));
   MOCK_METHOD2(MessageReplyChannelHandle,
-               int(Message* message, const BorrowedChannelHandle& handle));
+               Status<void>(Message* message,
+                            const BorrowedChannelHandle& handle));
   MOCK_METHOD2(MessageReplyChannelHandle,
-               int(Message* message, const RemoteChannelHandle& handle));
-  MOCK_METHOD3(ReadMessageData, ssize_t(Message* message, const iovec* vector,
-                                        size_t vector_length));
-  MOCK_METHOD3(WriteMessageData, ssize_t(Message* message, const iovec* vector,
-                                         size_t vector_length));
+               Status<void>(Message* message,
+                            const RemoteChannelHandle& handle));
+  MOCK_METHOD3(ReadMessageData,
+               Status<size_t>(Message* message, const iovec* vector,
+                              size_t vector_length));
+  MOCK_METHOD3(WriteMessageData,
+               Status<size_t>(Message* message, const iovec* vector,
+                              size_t vector_length));
   MOCK_METHOD2(PushFileHandle,
-               FileReference(Message* message, const LocalHandle& handle));
+               Status<FileReference>(Message* message,
+                                     const LocalHandle& handle));
   MOCK_METHOD2(PushFileHandle,
-               FileReference(Message* message, const BorrowedHandle& handle));
+               Status<FileReference>(Message* message,
+                                     const BorrowedHandle& handle));
   MOCK_METHOD2(PushFileHandle,
-               FileReference(Message* message, const RemoteHandle& handle));
+               Status<FileReference>(Message* message,
+                                     const RemoteHandle& handle));
   MOCK_METHOD2(PushChannelHandle,
-               ChannelReference(Message* message,
-                                const LocalChannelHandle& handle));
+               Status<ChannelReference>(Message* message,
+                                        const LocalChannelHandle& handle));
   MOCK_METHOD2(PushChannelHandle,
-               ChannelReference(Message* message,
-                                const BorrowedChannelHandle& handle));
+               Status<ChannelReference>(Message* message,
+                                        const BorrowedChannelHandle& handle));
   MOCK_METHOD2(PushChannelHandle,
-               ChannelReference(Message* message,
-                                const RemoteChannelHandle& handle));
+               Status<ChannelReference>(Message* message,
+                                        const RemoteChannelHandle& handle));
   MOCK_CONST_METHOD2(GetFileHandle,
                      LocalHandle(Message* message, FileReference ref));
   MOCK_CONST_METHOD2(GetChannelHandle,
@@ -57,7 +65,7 @@
                                         ChannelReference ref));
   MOCK_METHOD0(AllocateMessageState, void*());
   MOCK_METHOD1(FreeMessageState, void(void* state));
-  MOCK_METHOD0(Cancel, int());
+  MOCK_METHOD0(Cancel, Status<void>());
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/rpc/remote_method.h b/libs/vr/libpdx/private/pdx/rpc/remote_method.h
index 3eca9e5..505c63b 100644
--- a/libs/vr/libpdx/private/pdx/rpc/remote_method.h
+++ b/libs/vr/libpdx/private/pdx/rpc/remote_method.h
@@ -121,9 +121,9 @@
 // either during dispatch of the remote method handler or at a later time if the
 // message is moved for delayed response.
 inline void RemoteMethodError(Message& message, int error_code) {
-  const int ret = message.ReplyError(error_code);
-  ALOGE_IF(ret < 0, "RemoteMethodError: Failed to reply to message: %s",
-           strerror(-ret));
+  const auto status = message.ReplyError(error_code);
+  ALOGE_IF(!status, "RemoteMethodError: Failed to reply to message: %s",
+           status.GetErrorMessage().c_str());
 }
 
 // Returns a value from a remote method to the client. The usual method to
@@ -135,9 +135,9 @@
 template <typename RemoteMethodType, typename Return>
 EnableIfDirectReturn<typename RemoteMethodType::Return> RemoteMethodReturn(
     Message& message, const Return& return_value) {
-  const int ret = message.Reply(return_value);
-  ALOGE_IF(ret < 0, "RemoteMethodReturn: Failed to reply to message: %s",
-           strerror(-ret));
+  const auto status = message.Reply(return_value);
+  ALOGE_IF(!status, "RemoteMethodReturn: Failed to reply to message: %s",
+           status.GetErrorMessage().c_str());
 }
 
 // Overload for non-direct return types.
@@ -148,14 +148,10 @@
   rpc::ServicePayload<ReplyBuffer> payload(message);
   MakeArgumentEncoder<Signature>(&payload).EncodeReturn(return_value);
 
-  int ret;
-  auto size = message.Write(payload.Data(), payload.Size());
-  if (size < static_cast<decltype(size)>(payload.Size()))
-    ret = message.ReplyError(EIO);
-  else
-    ret = message.Reply(0);
-  ALOGE_IF(ret < 0, "RemoteMethodReturn: Failed to reply to message: %s",
-           strerror(-ret));
+  auto ret = message.WriteAll(payload.Data(), payload.Size());
+  auto status = message.Reply(ret);
+  ALOGE_IF(!status, "RemoteMethodReturn: Failed to reply to message: %s",
+           status.GetErrorMessage().c_str());
 }
 
 // Overload for Status<void> return types.
@@ -189,13 +185,13 @@
   rpc::ServicePayload<ReceiveBuffer> payload(message);
   payload.Resize(max_capacity);
 
-  auto size = message.Read(payload.Data(), payload.Size());
-  if (size < 0) {
-    RemoteMethodError(message, -size);
+  Status<size_t> read_status = message.Read(payload.Data(), payload.Size());
+  if (!read_status) {
+    RemoteMethodError(message, read_status.error());
     return;
   }
 
-  payload.Resize(size);
+  payload.Resize(read_status.get());
 
   ErrorType error;
   auto decoder = MakeArgumentDecoder<Signature>(&payload);
@@ -225,13 +221,13 @@
   rpc::ServicePayload<ReceiveBuffer> payload(message);
   payload.Resize(max_capacity);
 
-  auto size = message.Read(payload.Data(), payload.Size());
-  if (size < 0) {
-    RemoteMethodError(message, -size);
+  Status<size_t> read_status = message.Read(payload.Data(), payload.Size());
+  if (!read_status) {
+    RemoteMethodError(message, read_status.error());
     return;
   }
 
-  payload.Resize(size);
+  payload.Resize(read_status.get());
 
   ErrorType error;
   auto decoder = MakeArgumentDecoder<Signature>(&payload);
@@ -265,13 +261,13 @@
   rpc::ServicePayload<ReceiveBuffer> payload(message);
   payload.Resize(max_capacity);
 
-  auto size = message.Read(payload.Data(), payload.Size());
-  if (size < 0) {
-    RemoteMethodError(message, -size);
+  Status<size_t> read_status = message.Read(payload.Data(), payload.Size());
+  if (!read_status) {
+    RemoteMethodError(message, read_status.error());
     return;
   }
 
-  payload.Resize(size);
+  payload.Resize(read_status.get());
 
   ErrorType error;
   auto decoder = MakeArgumentDecoder<Signature>(&payload);
diff --git a/libs/vr/libpdx/private/pdx/rpc/serialization.h b/libs/vr/libpdx/private/pdx/rpc/serialization.h
index fccd028..f12aef1 100644
--- a/libs/vr/libpdx/private/pdx/rpc/serialization.h
+++ b/libs/vr/libpdx/private/pdx/rpc/serialization.h
@@ -247,7 +247,7 @@
 inline std::size_t GetSerializedSize(const EmptyVariant&);
 template <typename... Types>
 inline std::size_t GetSerializedSize(const Variant<Types...>&);
-template <typename T, typename Enabled>
+template <typename T, typename Enabled = EnableIfHasSerializableMembers<T>>
 inline constexpr std::size_t GetSerializedSize(const T&);
 template <typename T>
 inline constexpr std::size_t GetSerializedSize(const PointerWrapper<T>&);
@@ -293,7 +293,7 @@
 }
 
 // Overload for structs/classes with SerializableMembers defined.
-template <typename T, typename Enabled = EnableIfHasSerializableMembers<T>>
+template <typename T, typename Enabled>
 inline constexpr std::size_t GetSerializedSize(const T& value) {
   return SerializableTraits<T>::GetSerializedSize(value);
 }
@@ -836,7 +836,7 @@
 inline void SerializeObject(const EmptyVariant&, MessageWriter*, void*&);
 template <typename... Types>
 inline void SerializeObject(const Variant<Types...>&, MessageWriter*, void*&);
-template <typename T, typename Enabled>
+template <typename T, typename Enabled = EnableIfHasSerializableMembers<T>>
 inline void SerializeObject(const T&, MessageWriter*, void*&);
 template <typename T>
 inline void SerializeObject(const PointerWrapper<T>&, MessageWriter*, void*&);
@@ -887,7 +887,7 @@
 }
 
 // Overload for serializable structure/class types.
-template <typename T, typename Enabled = EnableIfHasSerializableMembers<T>>
+template <typename T, typename Enabled>
 inline void SerializeObject(const T& value, MessageWriter* writer,
                             void*& buffer) {
   SerializableTraits<T>::SerializeObject(value, writer, buffer);
@@ -905,8 +905,9 @@
 inline void SerializeObject(const FileHandle<Mode>& fd, MessageWriter* writer,
                             void*& buffer) {
   SerializeType(fd, buffer);
-  const FileReference value =
+  const Status<FileReference> status =
       writer->GetOutputResourceMapper()->PushFileHandle(fd);
+  FileReference value = status ? status.get() : -status.error();
   SerializeRaw(value, buffer);
 }
 
@@ -915,8 +916,9 @@
 inline void SerializeObject(const ChannelHandle<Mode>& handle,
                             MessageWriter* writer, void*& buffer) {
   SerializeType(handle, buffer);
-  const ChannelReference value =
+  const Status<ChannelReference> status =
       writer->GetOutputResourceMapper()->PushChannelHandle(handle);
+  ChannelReference value = status ? status.get() : -status.error();
   SerializeRaw(value, buffer);
 }
 
@@ -1377,7 +1379,7 @@
 }
 
 // Forward declarations for nested definitions.
-template <typename T, typename Enabled>
+template <typename T, typename Enabled = EnableIfHasSerializableMembers<T>>
 inline ErrorType DeserializeObject(T*, MessageReader*, const void*&,
                                    const void*&);
 template <typename T>
@@ -1436,7 +1438,7 @@
                                    const void*&);
 
 // Deserializes a Serializable type.
-template <typename T, typename Enable = EnableIfHasSerializableMembers<T>>
+template <typename T, typename Enable>
 inline ErrorType DeserializeObject(T* value, MessageReader* reader,
                                    const void*& start, const void*& end) {
   return SerializableTraits<T>::DeserializeObject(value, reader, start, end);
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index 09789e5..cb44a51 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -39,15 +39,11 @@
 template <typename... Types>
 struct HasType : std::false_type {};
 template <typename T, typename U>
-struct HasType<T, U> : std::is_same<T, U> {};
+struct HasType<T, U> : std::is_same<std::decay_t<T>, std::decay_t<U>> {};
 template <typename T, typename First, typename... Rest>
 struct HasType<T, First, Rest...>
-    : std::integral_constant<
-          bool, std::is_same<T, First>::value || HasType<T, Rest...>::value> {};
-
-template <typename T, typename... Types>
-using HasTypeIgnoreRef =
-    HasType<typename std::remove_reference<T>::type, Types...>;
+    : std::integral_constant<bool, HasType<T, First>::value ||
+                                       HasType<T, Rest...>::value> {};
 
 // Defines set operations on a set of Types...
 template <typename... Types>
@@ -59,8 +55,8 @@
   struct IsSubset<T> : HasType<T, Types...> {};
   template <typename First, typename... Rest>
   struct IsSubset<First, Rest...>
-      : std::integral_constant<
-            bool, IsSubset<First>::value && IsSubset<Rest...>::value> {};
+      : std::integral_constant<bool, IsSubset<First>::value &&
+                                         IsSubset<Rest...>::value> {};
 };
 
 // Determines the number of elements of Types... that are constructible from
@@ -80,18 +76,18 @@
 // Enable if T is an element of Types...
 template <typename R, typename T, typename... Types>
 using EnableIfElement =
-    typename std::enable_if<HasTypeIgnoreRef<T, Types...>::value, R>::type;
+    typename std::enable_if<HasType<T, Types...>::value, R>::type;
 // Enable if T is not an element of Types...
 template <typename R, typename T, typename... Types>
 using EnableIfNotElement =
-    typename std::enable_if<!HasTypeIgnoreRef<T, Types...>::value, R>::type;
+    typename std::enable_if<!HasType<T, Types...>::value, R>::type;
 
 // Enable if T is convertible to an element of Types... T is considered
 // convertible IIF a single element of Types... is assignable from T and T is
 // not a direct element of Types...
 template <typename R, typename T, typename... Types>
 using EnableIfConvertible =
-    typename std::enable_if<!HasTypeIgnoreRef<T, Types...>::value &&
+    typename std::enable_if<!HasType<T, Types...>::value &&
                                 ConstructibleCount<T, Types...>::value == 1,
                             R>::type;
 
@@ -102,7 +98,7 @@
 // in conversion.
 template <typename R, typename T, typename... Types>
 using EnableIfAssignable =
-    typename std::enable_if<HasTypeIgnoreRef<T, Types...>::value ||
+    typename std::enable_if<HasType<T, Types...>::value ||
                                 ConstructibleCount<T, Types...>::value == 1,
                             R>::type;
 
@@ -362,15 +358,13 @@
   template <typename T>
   using TypeTag = detail::TypeTag<T>;
   template <typename T>
-  using TypeTagIgnoreRef = TypeTag<typename std::remove_reference<T>::type>;
+  using DecayedTypeTag = TypeTag<std::decay_t<T>>;
   template <std::size_t I>
   using TypeForIndex = detail::TypeForIndex<I, Types...>;
   template <std::size_t I>
   using TypeTagForIndex = detail::TypeTagForIndex<I, Types...>;
   template <typename T>
   using HasType = detail::HasType<T, Types...>;
-  template <typename T>
-  using HasTypeIgnoreRef = detail::HasTypeIgnoreRef<T, Types...>;
   template <typename R, typename T>
   using EnableIfElement = detail::EnableIfElement<R, T, Types...>;
   template <typename R, typename T>
@@ -381,13 +375,12 @@
   struct Direct {};
   struct Convert {};
   template <typename T>
-  using SelectConstructor =
-      detail::Select<HasTypeIgnoreRef<T>::value, Direct, Convert>;
+  using SelectConstructor = detail::Select<HasType<T>::value, Direct, Convert>;
 
   // Constructs by type tag when T is an direct element of Types...
   template <typename T>
   explicit Variant(T&& value, Direct)
-      : value_(0, &index_, TypeTagIgnoreRef<T>{}, std::forward<T>(value)) {}
+      : value_(0, &index_, DecayedTypeTag<T>{}, std::forward<T>(value)) {}
   // Conversion constructor when T is not a direct element of Types...
   template <typename T>
   explicit Variant(T&& value, Convert)
@@ -421,7 +414,7 @@
   // convertible to multiple elements of Types.
   template <typename T>
   EnableIfElement<Variant&, T> operator=(T&& value) {
-    Assign(TypeTagIgnoreRef<T>{}, std::forward<T>(value));
+    Assign(DecayedTypeTag<T>{}, std::forward<T>(value));
     return *this;
   }
 
@@ -487,7 +480,7 @@
   template <typename T>
   constexpr std::int32_t index_of() const {
     static_assert(HasType<T>::value, "T is not an element type of Variant.");
-    return value_.template index(TypeTag<T>{});
+    return value_.template index(DecayedTypeTag<T>{});
   }
 
   // Returns the index of the active type. If the Variant is empty -1 is
@@ -509,14 +502,14 @@
   template <typename T>
   T* get() {
     if (is<T>())
-      return &value_.template get(TypeTag<T>{});
+      return &value_.template get(DecayedTypeTag<T>{});
     else
       return nullptr;
   }
   template <typename T>
   const T* get() const {
     if (is<T>())
-      return &value_.template get(TypeTag<T>{});
+      return &value_.template get(DecayedTypeTag<T>{});
     else
       return nullptr;
   }
@@ -537,7 +530,7 @@
 
  private:
   std::int32_t index_ = kEmptyIndex;
-  detail::Union<Types...> value_;
+  detail::Union<std::decay_t<Types>...> value_;
 
   // Constructs an element from the given arguments and sets the Variant to the
   // resulting type.
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index 175cedf..0d30614 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -98,29 +98,62 @@
   /*
    * Read/write payload, in either single buffer or iovec form.
    */
-  ssize_t ReadVector(const iovec* vector, size_t vector_length);
-  ssize_t Read(void* buffer, size_t length);
-  ssize_t WriteVector(const iovec* vector, size_t vector_length);
-  ssize_t Write(const void* buffer, size_t length);
+  Status<size_t> ReadVector(const iovec* vector, size_t vector_length);
+  Status<size_t> Read(void* buffer, size_t length);
+  Status<size_t> WriteVector(const iovec* vector, size_t vector_length);
+  Status<size_t> Write(const void* buffer, size_t length);
 
   template <size_t N>
-  inline ssize_t ReadVector(const iovec (&vector)[N]) {
+  inline Status<size_t> ReadVector(const iovec (&vector)[N]) {
     return ReadVector(vector, N);
   }
 
   template <size_t N>
-  inline ssize_t WriteVector(const iovec (&vector)[N]) {
+  inline Status<size_t> WriteVector(const iovec (&vector)[N]) {
     return WriteVector(vector, N);
   }
 
+  // Helper functions to read/write all requested bytes, and return EIO if not
+  // all were read/written.
+  Status<void> ReadVectorAll(const iovec* vector, size_t vector_length);
+  Status<void> WriteVectorAll(const iovec* vector, size_t vector_length);
+
+  inline Status<void> ReadAll(void* buffer, size_t length) {
+    Status<size_t> status = Read(buffer, length);
+    if (status && status.get() < length)
+      status.SetError(EIO);
+    Status<void> ret;
+    ret.PropagateError(status);
+    return ret;
+  }
+  inline Status<void> WriteAll(const void* buffer, size_t length) {
+    Status<size_t> status = Write(buffer, length);
+    if (status && status.get() < length)
+      status.SetError(EIO);
+    Status<void> ret;
+    ret.PropagateError(status);
+    return ret;
+  }
+
+  template <size_t N>
+  inline Status<void> ReadVectorAll(const iovec (&vector)[N]) {
+    return ReadVectorAll(vector, N);
+  }
+
+  template <size_t N>
+  inline Status<void> WriteVectorAll(const iovec (&vector)[N]) {
+    return WriteVectorAll(vector, N);
+  }
+
   // OutputResourceMapper
-  FileReference PushFileHandle(const LocalHandle& handle) override;
-  FileReference PushFileHandle(const BorrowedHandle& handle) override;
-  FileReference PushFileHandle(const RemoteHandle& handle) override;
-  ChannelReference PushChannelHandle(const LocalChannelHandle& handle) override;
-  ChannelReference PushChannelHandle(
+  Status<FileReference> PushFileHandle(const LocalHandle& handle) override;
+  Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override;
+  Status<FileReference> PushFileHandle(const RemoteHandle& handle) override;
+  Status<ChannelReference> PushChannelHandle(
+      const LocalChannelHandle& handle) override;
+  Status<ChannelReference> PushChannelHandle(
       const BorrowedChannelHandle& handle) override;
-  ChannelReference PushChannelHandle(
+  Status<ChannelReference> PushChannelHandle(
       const RemoteChannelHandle& handle) override;
 
   // InputResourceMapper
@@ -131,25 +164,29 @@
   /*
    * Various ways to reply to a message.
    */
-  int Reply(int return_code);
-  int ReplyError(unsigned error);
-  int ReplyFileDescriptor(unsigned int fd);
-  int Reply(const LocalHandle& handle);
-  int Reply(const BorrowedHandle& handle);
-  int Reply(const RemoteHandle& handle);
-  int Reply(const LocalChannelHandle& handle);
-  int Reply(const BorrowedChannelHandle& handle);
-  int Reply(const RemoteChannelHandle& handle);
+  Status<void> Reply(int return_code);
+  Status<void> ReplyError(unsigned int error);
+  Status<void> ReplyFileDescriptor(unsigned int fd);
+  Status<void> Reply(const LocalHandle& handle);
+  Status<void> Reply(const BorrowedHandle& handle);
+  Status<void> Reply(const RemoteHandle& handle);
+  Status<void> Reply(const LocalChannelHandle& handle);
+  Status<void> Reply(const BorrowedChannelHandle& handle);
+  Status<void> Reply(const RemoteChannelHandle& handle);
 
   template <typename T>
-  inline int Reply(const Status<T>& status) {
+  inline Status<void> Reply(const Status<T>& status) {
     return status ? Reply(status.get()) : ReplyError(status.error());
   }
 
+  inline Status<void> Reply(const Status<void>& status) {
+    return status ? Reply(0) : ReplyError(status.error());
+  }
+
   /*
    * Update the channel event bits with the given clear and set masks.
    */
-  int ModifyChannelEvents(int clear_mask, int set_mask);
+  Status<void> ModifyChannelEvents(int clear_mask, int set_mask);
 
   /*
    * Create a new channel and push it as a file descriptor to the client. See
@@ -264,7 +301,7 @@
    * these in multi-threaded services.
    */
   std::shared_ptr<Channel> GetChannel() const;
-  void SetChannel(const std::shared_ptr<Channel>& channnel);
+  Status<void> SetChannel(const std::shared_ptr<Channel>& channnel);
 
   /*
    * Get the Channel object for the channel associated with this message,
@@ -355,7 +392,8 @@
    * the Channel object until the channel is closed or another call replaces
    * the current value.
    */
-  int SetChannel(int channel_id, const std::shared_ptr<Channel>& channel);
+  Status<void> SetChannel(int channel_id,
+                          const std::shared_ptr<Channel>& channel);
 
   /*
    * Get the channel context for the given channel id. This method should be
@@ -404,7 +442,7 @@
    *
    * OnChannelClosed is not called in response to this method call.
    */
-  int CloseChannel(int channel_id);
+  Status<void> CloseChannel(int channel_id);
 
   /*
    * Update the event bits for the given channel (given by id), using the
@@ -413,7 +451,8 @@
    * This is useful for asynchronously signaling events that clients may be
    * waiting for using select/poll/epoll.
    */
-  int ModifyChannelEvents(int channel_id, int clear_mask, int set_mask);
+  Status<void> ModifyChannelEvents(int channel_id, int clear_mask,
+                                   int set_mask);
 
   /*
    * Create a new channel and push it as a file descriptor to the process
@@ -478,7 +517,7 @@
    * The default implementation simply calls defaultHandleMessage().
    * Subclasses should call the same for any unrecognized message opcodes.
    */
-  virtual int HandleMessage(Message& message);
+  virtual Status<void> HandleMessage(Message& message);
 
   /*
    * Handle an asynchronous message. Subclasses override this to receive
@@ -496,9 +535,9 @@
    * Provides default handling of CHANNEL_OPEN and CHANNEL_CLOSE, calling
    * OnChannelOpen() and OnChannelClose(), respectively.
    *
-   * For all other message opcodes, this method replies with -ENOTSUP.
+   * For all other message opcodes, this method replies with ENOTSUP.
    */
-  int DefaultHandleMessage(Message& message);
+  Status<void> DefaultHandleMessage(Message& message);
 
   /*
    * Called when system properties have changed. Subclasses should implement
@@ -515,7 +554,7 @@
    * Cancels the endpoint, unblocking any receiver threads waiting in
    * ReceiveAndDispatch().
    */
-  int Cancel();
+  Status<void> Cancel();
 
   /*
    * Iterator type for Channel map iterators.
@@ -564,14 +603,14 @@
    * If the endpoint is in blocking mode this call blocks until a message is
    * received, a signal is delivered to this thread, or the service is canceled.
    * If the endpoint is in non-blocking mode and a message is not pending this
-   * call returns immediately with -ETIMEDOUT.
+   * call returns immediately with ETIMEDOUT.
    */
-  int ReceiveAndDispatch();
+  Status<void> ReceiveAndDispatch();
 
  private:
   friend class Message;
 
-  bool HandleSystemMessage(Message& message);
+  Status<void> HandleSystemMessage(Message& message);
 
   Service(const Service&);
   void operator=(const Service&) = delete;
@@ -639,28 +678,28 @@
 
 #define REPLY_ERROR(message, error, error_label)                              \
   do {                                                                        \
-    int __ret = message.ReplyError(error);                                    \
-    CHECK_ERROR(__ret < 0, error_label,                                       \
+    auto __status = message.ReplyError(error);                                \
+    CHECK_ERROR(!__status, error_label,                                       \
                 PDX_ERROR_PREFIX " Failed to reply to message because: %s\n", \
-                strerror(-__ret));                                            \
+                __status.GetErrorMessage().c_str());                          \
     goto error_label;                                                         \
   } while (0)
 
 #define REPLY_ERROR_RETURN(message, error, ...)                          \
   do {                                                                   \
-    int __ret = message.ReplyError(error);                               \
-    ALOGE_IF(__ret < 0,                                                  \
+    auto __status = message.ReplyError(error);                           \
+    ALOGE_IF(!__status,                                                  \
              PDX_ERROR_PREFIX " Failed to reply to message because: %s", \
-             strerror(-__ret));                                          \
+             __status.GetErrorMessage().c_str());                        \
     return __VA_ARGS__;                                                  \
   } while (0)
 
 #define REPLY_MESSAGE(message, message_return_code, error_label)              \
   do {                                                                        \
-    int __ret = message.Reply(message_return_code);                           \
-    CHECK_ERROR(__ret < 0, error_label,                                       \
+    auto __status = message.Reply(message_return_code);                       \
+    CHECK_ERROR(!__status, error_label,                                       \
                 PDX_ERROR_PREFIX " Failed to reply to message because: %s\n", \
-                strerror(-__ret));                                            \
+                __status.GetErrorMessage().c_str());                          \
     goto error_label;                                                         \
   } while (0)
 
@@ -669,10 +708,10 @@
 
 #define REPLY_MESSAGE_RETURN(message, message_return_code, ...)          \
   do {                                                                   \
-    int __ret = message.Reply(message_return_code);                      \
-    ALOGE_IF(__ret < 0,                                                  \
+    auto __status = message.Reply(message_return_code);                  \
+    ALOGE_IF(!__status,                                                  \
              PDX_ERROR_PREFIX " Failed to reply to message because: %s", \
-             strerror(-__ret));                                          \
+             __status.GetErrorMessage().c_str());                        \
     return __VA_ARGS__;                                                  \
   } while (0)
 
@@ -681,19 +720,19 @@
 
 #define REPLY_FD(message, push_fd, error_label)                               \
   do {                                                                        \
-    int __ret = message.ReplyFileDescriptor(push_fd);                         \
-    CHECK_ERROR(__ret < 0, error_label,                                       \
+    auto __status = message.ReplyFileDescriptor(push_fd);                     \
+    CHECK_ERROR(!__status, error_label,                                       \
                 PDX_ERROR_PREFIX " Failed to reply to message because: %s\n", \
-                strerror(-__ret));                                            \
+                __status.GetErrorMessage().c_str());                          \
     goto error_label;                                                         \
   } while (0)
 
 #define REPLY_FD_RETURN(message, push_fd, ...)                           \
   do {                                                                   \
-    int __ret = message.ReplyFileDescriptor(push_fd);                    \
-    ALOGE_IF(__ret < 0,                                                  \
+    auto __status = message.ReplyFileDescriptor(push_fd);                \
+    ALOGE_IF(__status < 0,                                               \
              PDX_ERROR_PREFIX " Failed to reply to message because: %s", \
-             strerror(-__ret));                                          \
+             __status.GetErrorMessage().c_str());                        \
     return __VA_ARGS__;                                                  \
   } while (0)
 
diff --git a/libs/vr/libpdx/private/pdx/service_endpoint.h b/libs/vr/libpdx/private/pdx/service_endpoint.h
index 613be7c..28bd6bc 100644
--- a/libs/vr/libpdx/private/pdx/service_endpoint.h
+++ b/libs/vr/libpdx/private/pdx/service_endpoint.h
@@ -44,20 +44,20 @@
   // Associates a Service instance with an endpoint by setting the service
   // context pointer to the address of the Service. Only one Service may be
   // associated with a given endpoint.
-  virtual int SetService(Service* service) = 0;
+  virtual Status<void> SetService(Service* service) = 0;
 
   // Set the channel context for the given channel.
-  virtual int SetChannel(int channel_id, Channel* channel) = 0;
+  virtual Status<void> SetChannel(int channel_id, Channel* channel) = 0;
 
   // Close a channel, signaling the client file object and freeing the channel
   // id. Once closed, the client side of the channel always returns the error
   // ESHUTDOWN and signals the poll/epoll events POLLHUP and POLLFREE.
-  virtual int CloseChannel(int channel_id) = 0;
+  virtual Status<void> CloseChannel(int channel_id) = 0;
 
   // Update the event bits for the given channel (given by id), using the
   // given clear and set masks.
-  virtual int ModifyChannelEvents(int channel_id, int clear_mask,
-                                  int set_mask) = 0;
+  virtual Status<void> ModifyChannelEvents(int channel_id, int clear_mask,
+                                           int set_mask) = 0;
 
   // Create a new channel and push it as a file descriptor to the process
   // sending the |message|. |flags| may be set to O_NONBLOCK and/or
@@ -77,54 +77,49 @@
   virtual Status<int> CheckChannel(const Message* message, ChannelReference ref,
                                    Channel** channel) = 0;
 
-  // The default message handler. It is important that all messages
-  // (eventually) get a reply. This method should be called for any unrecognized
-  // opcodes or otherwise unhandled messages to prevent erroneous requests from
-  // blocking indefinitely.
-  virtual int DefaultHandleMessage(const MessageInfo& info) = 0;
-
   // Receives a message on the given endpoint file descriptor.
-  virtual int MessageReceive(Message* message) = 0;
+  virtual Status<void> MessageReceive(Message* message) = 0;
 
   // Replies to the message with a return code.
-  virtual int MessageReply(Message* message, int return_code) = 0;
+  virtual Status<void> MessageReply(Message* message, int return_code) = 0;
 
   // Replies to the message with a file descriptor.
-  virtual int MessageReplyFd(Message* message, unsigned int push_fd) = 0;
+  virtual Status<void> MessageReplyFd(Message* message,
+                                      unsigned int push_fd) = 0;
 
   // Replies to the message with a local channel handle.
-  virtual int MessageReplyChannelHandle(Message* message,
-                                        const LocalChannelHandle& handle) = 0;
+  virtual Status<void> MessageReplyChannelHandle(
+      Message* message, const LocalChannelHandle& handle) = 0;
 
   // Replies to the message with a borrowed local channel handle.
-  virtual int MessageReplyChannelHandle(
+  virtual Status<void> MessageReplyChannelHandle(
       Message* message, const BorrowedChannelHandle& handle) = 0;
 
   // Replies to the message with a remote channel handle.
-  virtual int MessageReplyChannelHandle(Message* message,
-                                        const RemoteChannelHandle& handle) = 0;
+  virtual Status<void> MessageReplyChannelHandle(
+      Message* message, const RemoteChannelHandle& handle) = 0;
 
   // Reads message data into an array of memory buffers.
-  virtual ssize_t ReadMessageData(Message* message, const iovec* vector,
-                                  size_t vector_length) = 0;
+  virtual Status<size_t> ReadMessageData(Message* message, const iovec* vector,
+                                         size_t vector_length) = 0;
 
   // Sends reply data for message.
-  virtual ssize_t WriteMessageData(Message* message, const iovec* vector,
-                                   size_t vector_length) = 0;
+  virtual Status<size_t> WriteMessageData(Message* message, const iovec* vector,
+                                          size_t vector_length) = 0;
 
   // Records a file descriptor into the message buffer and returns the remapped
   // reference to be sent to the remote process.
-  virtual FileReference PushFileHandle(Message* message,
-                                       const LocalHandle& handle) = 0;
-  virtual FileReference PushFileHandle(Message* message,
-                                       const BorrowedHandle& handle) = 0;
-  virtual FileReference PushFileHandle(Message* message,
-                                       const RemoteHandle& handle) = 0;
-  virtual ChannelReference PushChannelHandle(
+  virtual Status<FileReference> PushFileHandle(Message* message,
+                                               const LocalHandle& handle) = 0;
+  virtual Status<FileReference> PushFileHandle(
+      Message* message, const BorrowedHandle& handle) = 0;
+  virtual Status<FileReference> PushFileHandle(Message* message,
+                                               const RemoteHandle& handle) = 0;
+  virtual Status<ChannelReference> PushChannelHandle(
       Message* message, const LocalChannelHandle& handle) = 0;
-  virtual ChannelReference PushChannelHandle(
+  virtual Status<ChannelReference> PushChannelHandle(
       Message* message, const BorrowedChannelHandle& handle) = 0;
-  virtual ChannelReference PushChannelHandle(
+  virtual Status<ChannelReference> PushChannelHandle(
       Message* message, const RemoteChannelHandle& handle) = 0;
 
   // Obtains a file descriptor/channel handle from a message for the given
@@ -140,7 +135,7 @@
 
   // Cancels the endpoint, unblocking any receiver threads waiting for a
   // message.
-  virtual int Cancel() = 0;
+  virtual Status<void> Cancel() = 0;
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/status.h b/libs/vr/libpdx/private/pdx/status.h
index ca2832c..067fe25 100644
--- a/libs/vr/libpdx/private/pdx/status.h
+++ b/libs/vr/libpdx/private/pdx/status.h
@@ -103,6 +103,17 @@
   // is not empty nor containing a valid value).
   int error() const { return std::max(error_, 0); }
 
+  // Returns the error code as ErrorStatus object. This is a helper method
+  // to aid in propagation of error codes between Status<T> of different types
+  // as in the following example:
+  //    Status<int> foo() {
+  //      Status<void> status = bar();
+  //      if(!status)
+  //        return status.error_status();
+  //      return 12;
+  //    }
+  inline ErrorStatus error_status() const { return ErrorStatus{error()}; }
+
   // Returns the error message associated with error code stored in the object.
   // The message is the same as the string returned by strerror(status.error()).
   // Can be called only when an error is actually stored (that is, the object
@@ -142,6 +153,7 @@
   bool empty() const { return false; }
   explicit operator bool() const { return ok(); }
   int error() const { return std::max(error_, 0); }
+  inline ErrorStatus error_status() const { return ErrorStatus{error()}; }
   std::string GetErrorMessage() const {
     std::string message;
     if (error_ > 0)
diff --git a/libs/vr/libpdx/private/pdx/utility.h b/libs/vr/libpdx/private/pdx/utility.h
index c8c717c..305c3b8 100644
--- a/libs/vr/libpdx/private/pdx/utility.h
+++ b/libs/vr/libpdx/private/pdx/utility.h
@@ -150,29 +150,29 @@
 
 class NoOpOutputResourceMapper : public OutputResourceMapper {
  public:
-  FileReference PushFileHandle(const LocalHandle& handle) override {
+  Status<FileReference> PushFileHandle(const LocalHandle& handle) override {
     return handle.Get();
   }
 
-  FileReference PushFileHandle(const BorrowedHandle& handle) override {
+  Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override {
     return handle.Get();
   }
 
-  FileReference PushFileHandle(const RemoteHandle& handle) override {
+  Status<FileReference> PushFileHandle(const RemoteHandle& handle) override {
     return handle.Get();
   }
 
-  ChannelReference PushChannelHandle(
+  Status<ChannelReference> PushChannelHandle(
       const LocalChannelHandle& handle) override {
     return handle.value();
   }
 
-  ChannelReference PushChannelHandle(
+  Status<ChannelReference> PushChannelHandle(
       const BorrowedChannelHandle& handle) override {
     return handle.value();
   }
 
-  ChannelReference PushChannelHandle(
+  Status<ChannelReference> PushChannelHandle(
       const RemoteChannelHandle& handle) override {
     return handle.value();
   }
@@ -278,7 +278,7 @@
   OutputResourceMapper* GetOutputResourceMapper() override { return this; }
 
   // OutputResourceMapper
-  FileReference PushFileHandle(const LocalHandle& handle) override {
+  Status<FileReference> PushFileHandle(const LocalHandle& handle) override {
     if (handle) {
       const int ref = file_handles_.size();
       file_handles_.push_back(handle.Get());
@@ -288,7 +288,7 @@
     }
   }
 
-  FileReference PushFileHandle(const BorrowedHandle& handle) override {
+  Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override {
     if (handle) {
       const int ref = file_handles_.size();
       file_handles_.push_back(handle.Get());
@@ -298,11 +298,11 @@
     }
   }
 
-  FileReference PushFileHandle(const RemoteHandle& handle) override {
+  Status<FileReference> PushFileHandle(const RemoteHandle& handle) override {
     return handle.Get();
   }
 
-  ChannelReference PushChannelHandle(
+  Status<ChannelReference> PushChannelHandle(
       const LocalChannelHandle& handle) override {
     if (handle) {
       const int ref = file_handles_.size();
@@ -313,7 +313,7 @@
     }
   }
 
-  ChannelReference PushChannelHandle(
+  Status<ChannelReference> PushChannelHandle(
       const BorrowedChannelHandle& handle) override {
     if (handle) {
       const int ref = file_handles_.size();
@@ -324,7 +324,7 @@
     }
   }
 
-  ChannelReference PushChannelHandle(
+  Status<ChannelReference> PushChannelHandle(
       const RemoteChannelHandle& handle) override {
     return handle.value();
   }
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index daf9af8..fab4770 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -9,7 +9,6 @@
 #include <cstdint>
 
 #include <pdx/trace.h>
-#include "errno_guard.h"
 
 #define TRACE 0
 
@@ -60,7 +59,7 @@
           "ERROR: Service \"%s\" failed to reply to message: op=%d pid=%d "
           "cid=%d\n",
           svc->name_.c_str(), info_.op, info_.pid, info_.cid);
-      svc->endpoint()->DefaultHandleMessage(info_);
+      svc->DefaultHandleMessage(*this);
     }
     svc->endpoint()->FreeMessageState(state_);
   }
@@ -77,112 +76,138 @@
   return ImpulseBegin() + (IsImpulse() ? GetSendLength() : 0);
 }
 
-ssize_t Message::ReadVector(const struct iovec* vector, size_t vector_length) {
+Status<size_t> Message::ReadVector(const struct iovec* vector,
+                                   size_t vector_length) {
   PDX_TRACE_NAME("Message::ReadVector");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
-    const ssize_t ret =
-        svc->endpoint()->ReadMessageData(this, vector, vector_length);
-    return ReturnCodeOrError(ret);
+    return svc->endpoint()->ReadMessageData(this, vector, vector_length);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
-ssize_t Message::Read(void* buffer, size_t length) {
+Status<void> Message::ReadVectorAll(const struct iovec* vector,
+                                    size_t vector_length) {
+  PDX_TRACE_NAME("Message::ReadVectorAll");
+  if (auto svc = service_.lock()) {
+    const auto status =
+        svc->endpoint()->ReadMessageData(this, vector, vector_length);
+    if (!status)
+      return status.error_status();
+    size_t size_to_read = 0;
+    for (size_t i = 0; i < vector_length; i++)
+      size_to_read += vector[i].iov_len;
+    if (status.get() < size_to_read)
+      return ErrorStatus{EIO};
+    return {};
+  } else {
+    return ErrorStatus{ESHUTDOWN};
+  }
+}
+
+Status<size_t> Message::Read(void* buffer, size_t length) {
   PDX_TRACE_NAME("Message::Read");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
     const struct iovec vector = {buffer, length};
-    const ssize_t ret = svc->endpoint()->ReadMessageData(this, &vector, 1);
-    return ReturnCodeOrError(ret);
+    return svc->endpoint()->ReadMessageData(this, &vector, 1);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
-ssize_t Message::WriteVector(const struct iovec* vector, size_t vector_length) {
+Status<size_t> Message::WriteVector(const struct iovec* vector,
+                                    size_t vector_length) {
   PDX_TRACE_NAME("Message::WriteVector");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
-    const ssize_t ret =
-        svc->endpoint()->WriteMessageData(this, vector, vector_length);
-    return ReturnCodeOrError(ret);
+    return svc->endpoint()->WriteMessageData(this, vector, vector_length);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
-ssize_t Message::Write(const void* buffer, size_t length) {
+Status<void> Message::WriteVectorAll(const struct iovec* vector,
+                                     size_t vector_length) {
+  PDX_TRACE_NAME("Message::WriteVector");
+  if (auto svc = service_.lock()) {
+    const auto status =
+        svc->endpoint()->WriteMessageData(this, vector, vector_length);
+    if (!status)
+      return status.error_status();
+    size_t size_to_write = 0;
+    for (size_t i = 0; i < vector_length; i++)
+      size_to_write += vector[i].iov_len;
+    if (status.get() < size_to_write)
+      return ErrorStatus{EIO};
+    return {};
+  } else {
+    return ErrorStatus{ESHUTDOWN};
+  }
+}
+
+Status<size_t> Message::Write(const void* buffer, size_t length) {
   PDX_TRACE_NAME("Message::Write");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
     const struct iovec vector = {const_cast<void*>(buffer), length};
-    const ssize_t ret = svc->endpoint()->WriteMessageData(this, &vector, 1);
-    return ReturnCodeOrError(ret);
+    return svc->endpoint()->WriteMessageData(this, &vector, 1);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
-FileReference Message::PushFileHandle(const LocalHandle& handle) {
+Status<FileReference> Message::PushFileHandle(const LocalHandle& handle) {
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
+    return svc->endpoint()->PushFileHandle(this, handle);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
-FileReference Message::PushFileHandle(const BorrowedHandle& handle) {
+Status<FileReference> Message::PushFileHandle(const BorrowedHandle& handle) {
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
+    return svc->endpoint()->PushFileHandle(this, handle);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
-FileReference Message::PushFileHandle(const RemoteHandle& handle) {
+Status<FileReference> Message::PushFileHandle(const RemoteHandle& handle) {
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
+    return svc->endpoint()->PushFileHandle(this, handle);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
-ChannelReference Message::PushChannelHandle(const LocalChannelHandle& handle) {
+Status<ChannelReference> Message::PushChannelHandle(
+    const LocalChannelHandle& handle) {
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
+    return svc->endpoint()->PushChannelHandle(this, handle);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
-ChannelReference Message::PushChannelHandle(
+Status<ChannelReference> Message::PushChannelHandle(
     const BorrowedChannelHandle& handle) {
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
+    return svc->endpoint()->PushChannelHandle(this, handle);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
-ChannelReference Message::PushChannelHandle(const RemoteChannelHandle& handle) {
+Status<ChannelReference> Message::PushChannelHandle(
+    const RemoteChannelHandle& handle) {
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
+    return svc->endpoint()->PushChannelHandle(this, handle);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
@@ -193,7 +218,6 @@
     return false;
 
   if (ref >= 0) {
-    ErrnoGuard errno_guard;
     *handle = svc->endpoint()->GetFileHandle(this, ref);
     if (!handle->IsValid())
       return false;
@@ -211,7 +235,6 @@
     return false;
 
   if (ref >= 0) {
-    ErrnoGuard errno_guard;
     *handle = svc->endpoint()->GetChannelHandle(this, ref);
     if (!handle->valid())
       return false;
@@ -221,141 +244,137 @@
   return true;
 }
 
-int Message::Reply(int return_code) {
+Status<void> Message::Reply(int return_code) {
   PDX_TRACE_NAME("Message::Reply");
   auto svc = service_.lock();
   if (!replied_ && svc) {
-    ErrnoGuard errno_guard;
-    const int ret = svc->endpoint()->MessageReply(this, return_code);
-    replied_ = ret == 0;
-    return ReturnCodeOrError(ret);
+    const auto ret = svc->endpoint()->MessageReply(this, return_code);
+    replied_ = ret.ok();
+    return ret;
   } else {
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   }
 }
 
-int Message::ReplyFileDescriptor(unsigned int fd) {
+Status<void> Message::ReplyFileDescriptor(unsigned int fd) {
   PDX_TRACE_NAME("Message::ReplyFileDescriptor");
   auto svc = service_.lock();
   if (!replied_ && svc) {
-    ErrnoGuard errno_guard;
-    const int ret = svc->endpoint()->MessageReplyFd(this, fd);
-    replied_ = ret == 0;
-    return ReturnCodeOrError(ret);
+    const auto ret = svc->endpoint()->MessageReplyFd(this, fd);
+    replied_ = ret.ok();
+    return ret;
   } else {
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   }
 }
 
-int Message::ReplyError(unsigned error) {
+Status<void> Message::ReplyError(unsigned int error) {
   PDX_TRACE_NAME("Message::ReplyError");
   auto svc = service_.lock();
   if (!replied_ && svc) {
-    ErrnoGuard errno_guard;
-    const int ret = svc->endpoint()->MessageReply(this, -error);
-    replied_ = ret == 0;
-    return ReturnCodeOrError(ret);
+    const auto ret =
+        svc->endpoint()->MessageReply(this, -static_cast<int>(error));
+    replied_ = ret.ok();
+    return ret;
   } else {
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   }
 }
 
-int Message::Reply(const LocalHandle& handle) {
+Status<void> Message::Reply(const LocalHandle& handle) {
   PDX_TRACE_NAME("Message::ReplyFileHandle");
   auto svc = service_.lock();
   if (!replied_ && svc) {
-    ErrnoGuard errno_guard;
-    int ret;
+    Status<void> ret;
 
     if (handle)
       ret = svc->endpoint()->MessageReplyFd(this, handle.Get());
     else
       ret = svc->endpoint()->MessageReply(this, handle.Get());
 
-    replied_ = ret == 0;
-    return ReturnCodeOrError(ret);
+    replied_ = ret.ok();
+    return ret;
   } else {
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   }
 }
 
-int Message::Reply(const BorrowedHandle& handle) {
+Status<void> Message::Reply(const BorrowedHandle& handle) {
   PDX_TRACE_NAME("Message::ReplyFileHandle");
   auto svc = service_.lock();
   if (!replied_ && svc) {
-    ErrnoGuard errno_guard;
-    int ret;
+    Status<void> ret;
 
     if (handle)
       ret = svc->endpoint()->MessageReplyFd(this, handle.Get());
     else
       ret = svc->endpoint()->MessageReply(this, handle.Get());
 
-    replied_ = ret == 0;
-    return ReturnCodeOrError(ret);
+    replied_ = ret.ok();
+    return ret;
   } else {
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   }
 }
 
-int Message::Reply(const RemoteHandle& handle) {
+Status<void> Message::Reply(const RemoteHandle& handle) {
   PDX_TRACE_NAME("Message::ReplyFileHandle");
   auto svc = service_.lock();
   if (!replied_ && svc) {
-    ErrnoGuard errno_guard;
-    const int ret = svc->endpoint()->MessageReply(this, handle.Get());
-    replied_ = ret == 0;
-    return ReturnCodeOrError(ret);
+    Status<void> ret;
+
+    if (handle)
+      ret = svc->endpoint()->MessageReply(this, handle.Get());
+    else
+      ret = svc->endpoint()->MessageReply(this, handle.Get());
+
+    replied_ = ret.ok();
+    return ret;
   } else {
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   }
 }
 
-int Message::Reply(const LocalChannelHandle& handle) {
+Status<void> Message::Reply(const LocalChannelHandle& handle) {
   auto svc = service_.lock();
   if (!replied_ && svc) {
-    ErrnoGuard errno_guard;
-    const int ret = svc->endpoint()->MessageReplyChannelHandle(this, handle);
-    replied_ = ret == 0;
-    return ReturnCodeOrError(ret);
+    const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle);
+    replied_ = ret.ok();
+    return ret;
   } else {
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   }
 }
 
-int Message::Reply(const BorrowedChannelHandle& handle) {
+Status<void> Message::Reply(const BorrowedChannelHandle& handle) {
   auto svc = service_.lock();
   if (!replied_ && svc) {
-    ErrnoGuard errno_guard;
-    const int ret = svc->endpoint()->MessageReplyChannelHandle(this, handle);
-    replied_ = ret == 0;
-    return ReturnCodeOrError(ret);
+    const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle);
+    replied_ = ret.ok();
+    return ret;
   } else {
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   }
 }
 
-int Message::Reply(const RemoteChannelHandle& handle) {
+Status<void> Message::Reply(const RemoteChannelHandle& handle) {
   auto svc = service_.lock();
   if (!replied_ && svc) {
-    ErrnoGuard errno_guard;
-    const int ret = svc->endpoint()->MessageReplyChannelHandle(this, handle);
-    replied_ = ret == 0;
-    return ReturnCodeOrError(ret);
+    const auto ret = svc->endpoint()->MessageReplyChannelHandle(this, handle);
+    replied_ = ret.ok();
+    return ret;
   } else {
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   }
 }
 
-int Message::ModifyChannelEvents(int clear_mask, int set_mask) {
+Status<void> Message::ModifyChannelEvents(int clear_mask, int set_mask) {
   PDX_TRACE_NAME("Message::ModifyChannelEvents");
   if (auto svc = service_.lock()) {
-    ErrnoGuard errno_guard;
-    const int ret =
-        svc->endpoint()->ModifyChannelEvents(info_.cid, clear_mask, set_mask);
-    return ReturnCodeOrError(ret);
+    return svc->endpoint()->ModifyChannelEvents(info_.cid, clear_mask,
+                                                set_mask);
   } else {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 }
 
@@ -416,11 +435,12 @@
 
 std::shared_ptr<Channel> Message::GetChannel() const { return channel_.lock(); }
 
-void Message::SetChannel(const std::shared_ptr<Channel>& chan) {
+Status<void> Message::SetChannel(const std::shared_ptr<Channel>& chan) {
   channel_ = chan;
-
+  Status<void> status;
   if (auto svc = service_.lock())
-    svc->SetChannel(info_.cid, chan);
+    status = svc->SetChannel(info_.cid, chan);
+  return status;
 }
 
 std::shared_ptr<Service> Message::GetService() const { return service_.lock(); }
@@ -432,16 +452,16 @@
   if (!endpoint_)
     return;
 
-  const int ret = endpoint_->SetService(this);
-  ALOGE_IF(ret < 0, "Failed to set service context because: %s",
-           strerror(-ret));
+  const auto status = endpoint_->SetService(this);
+  ALOGE_IF(!status, "Failed to set service context because: %s",
+           status.GetErrorMessage().c_str());
 }
 
 Service::~Service() {
   if (endpoint_) {
-    const int ret = endpoint_->SetService(nullptr);
-    ALOGE_IF(ret < 0, "Failed to clear service context because: %s",
-             strerror(-ret));
+    const auto status = endpoint_->SetService(nullptr);
+    ALOGE_IF(!status, "Failed to clear service context because: %s",
+             status.GetErrorMessage().c_str());
   }
 }
 
@@ -459,32 +479,28 @@
 void Service::OnChannelClose(Message& /*message*/,
                              const std::shared_ptr<Channel>& /*channel*/) {}
 
-int Service::SetChannel(int channel_id,
-                        const std::shared_ptr<Channel>& channel) {
+Status<void> Service::SetChannel(int channel_id,
+                                 const std::shared_ptr<Channel>& channel) {
   PDX_TRACE_NAME("Service::SetChannel");
-  ErrnoGuard errno_guard;
   std::lock_guard<std::mutex> autolock(channels_mutex_);
 
-  const int ret = endpoint_->SetChannel(channel_id, channel.get());
-  if (ret == -1) {
+  const auto status = endpoint_->SetChannel(channel_id, channel.get());
+  if (!status) {
     ALOGE("%s::SetChannel: Failed to set channel context: %s\n", name_.c_str(),
-          strerror(errno));
+          status.GetErrorMessage().c_str());
 
     // It's possible someone mucked with things behind our back by calling the C
     // API directly. Since we know the channel id isn't valid, make sure we
     // don't have it in the channels map.
-    if (errno == ENOENT)
+    if (status.error() == ENOENT)
       channels_.erase(channel_id);
-
-    return ReturnCodeOrError(ret);
+  } else {
+    if (channel != nullptr)
+      channels_[channel_id] = channel;
+    else
+      channels_.erase(channel_id);
   }
-
-  if (channel != nullptr)
-    channels_[channel_id] = channel;
-  else
-    channels_.erase(channel_id);
-
-  return ret;
+  return status;
 }
 
 std::shared_ptr<Channel> Service::GetChannel(int channel_id) const {
@@ -498,21 +514,21 @@
     return nullptr;
 }
 
-int Service::CloseChannel(int channel_id) {
+Status<void> Service::CloseChannel(int channel_id) {
   PDX_TRACE_NAME("Service::CloseChannel");
-  ErrnoGuard errno_guard;
   std::lock_guard<std::mutex> autolock(channels_mutex_);
 
-  const int ret = endpoint_->CloseChannel(channel_id);
+  const auto status = endpoint_->CloseChannel(channel_id);
 
   // Always erase the map entry, in case someone mucked with things behind our
   // back using the C API directly.
   channels_.erase(channel_id);
 
-  return ReturnCodeOrError(ret);
+  return status;
 }
 
-int Service::ModifyChannelEvents(int channel_id, int clear_mask, int set_mask) {
+Status<void> Service::ModifyChannelEvents(int channel_id, int clear_mask,
+                                          int set_mask) {
   PDX_TRACE_NAME("Service::ModifyChannelEvents");
   return endpoint_->ModifyChannelEvents(channel_id, clear_mask, set_mask);
 }
@@ -521,7 +537,6 @@
     Message* message, int flags, const std::shared_ptr<Channel>& channel,
     int* channel_id) {
   PDX_TRACE_NAME("Service::PushChannel");
-  ErrnoGuard errno_guard;
 
   std::lock_guard<std::mutex> autolock(channels_mutex_);
 
@@ -542,7 +557,6 @@
 Status<int> Service::CheckChannel(const Message* message, ChannelReference ref,
                                   std::shared_ptr<Channel>* channel) const {
   PDX_TRACE_NAME("Service::CheckChannel");
-  ErrnoGuard errno_guard;
 
   // Synchronization to maintain consistency between the kernel's channel
   // context pointer and the userspace channels_ map. Other threads may attempt
@@ -565,13 +579,13 @@
 
 std::string Service::DumpState(size_t /*max_length*/) { return ""; }
 
-int Service::HandleMessage(Message& message) {
+Status<void> Service::HandleMessage(Message& message) {
   return DefaultHandleMessage(message);
 }
 
 void Service::HandleImpulse(Message& /*impulse*/) {}
 
-bool Service::HandleSystemMessage(Message& message) {
+Status<void> Service::HandleSystemMessage(Message& message) {
   const MessageInfo& info = message.GetInfo();
 
   switch (info.op) {
@@ -579,8 +593,7 @@
       ALOGD("%s::OnChannelOpen: pid=%d cid=%d\n", name_.c_str(), info.pid,
             info.cid);
       message.SetChannel(OnChannelOpen(message));
-      message.Reply(0);
-      return true;
+      return message.Reply(0);
     }
 
     case opcodes::CHANNEL_CLOSE: {
@@ -588,8 +601,7 @@
             info.cid);
       OnChannelClose(message, Channel::GetFromMessageInfo(info));
       message.SetChannel(nullptr);
-      message.Reply(0);
-      return true;
+      return message.Reply(0);
     }
 
     case opcodes::REPORT_SYSPROP_CHANGE:
@@ -597,8 +609,7 @@
             info.pid, info.cid);
       OnSysPropChange();
       android::report_sysprop_change();
-      message.Reply(0);
-      return true;
+      return message.Reply(0);
 
     case opcodes::DUMP_STATE: {
       ALOGD("%s:DUMP_STATE: pid=%d cid=%d\n", name_.c_str(), info.pid,
@@ -607,21 +618,20 @@
       const size_t response_size = response.size() < message.GetReceiveLength()
                                        ? response.size()
                                        : message.GetReceiveLength();
-      const ssize_t bytes_written =
+      const Status<size_t> status =
           message.Write(response.data(), response_size);
-      if (bytes_written < static_cast<ssize_t>(response_size))
-        message.ReplyError(EIO);
+      if (status && status.get() < response_size)
+        return message.ReplyError(EIO);
       else
-        message.Reply(bytes_written);
-      return true;
+        return message.Reply(status);
     }
 
     default:
-      return false;
+      return ErrorStatus{EOPNOTSUPP};
   }
 }
 
-int Service::DefaultHandleMessage(Message& message) {
+Status<void> Service::DefaultHandleMessage(Message& message) {
   const MessageInfo& info = message.GetInfo();
 
   ALOGD_IF(TRACE, "Service::DefaultHandleMessage: pid=%d cid=%d op=%d\n",
@@ -632,23 +642,21 @@
     case opcodes::CHANNEL_CLOSE:
     case opcodes::REPORT_SYSPROP_CHANGE:
     case opcodes::DUMP_STATE:
-      HandleSystemMessage(message);
-      return 0;
+      return HandleSystemMessage(message);
 
     default:
-      return message.ReplyError(ENOTSUP);
+      return message.ReplyError(EOPNOTSUPP);
   }
 }
 
 void Service::OnSysPropChange() {}
 
-int Service::ReceiveAndDispatch() {
-  ErrnoGuard errno_guard;
+Status<void> Service::ReceiveAndDispatch() {
   Message message;
-  const int ret = endpoint_->MessageReceive(&message);
-  if (ret < 0) {
-    ALOGE("Failed to receive message: %s\n", strerror(errno));
-    return ReturnCodeOrError(ret);
+  const auto status = endpoint_->MessageReceive(&message);
+  if (!status) {
+    ALOGE("Failed to receive message: %s\n", status.GetErrorMessage().c_str());
+    return status;
   }
 
   std::shared_ptr<Service> service = message.GetService();
@@ -657,24 +665,20 @@
     ALOGE("Service::ReceiveAndDispatch: service context is NULL!!!\n");
     // Don't block the sender indefinitely in this error case.
     endpoint_->MessageReply(&message, -EINVAL);
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   }
 
   if (message.IsImpulse()) {
     service->HandleImpulse(message);
-    return 0;
+    return {};
   } else if (service->HandleSystemMessage(message)) {
-    return 0;
+    return {};
   } else {
     return service->HandleMessage(message);
   }
 }
 
-int Service::Cancel() {
-  ErrnoGuard errno_guard;
-  const int ret = endpoint_->Cancel();
-  return ReturnCodeOrError(ret);
-}
+Status<void> Service::Cancel() { return endpoint_->Cancel(); }
 
 }  // namespace pdx
 }  // namespace android
diff --git a/libs/vr/libpdx/service_tests.cpp b/libs/vr/libpdx/service_tests.cpp
index fc0c8db..c7412b7 100644
--- a/libs/vr/libpdx/service_tests.cpp
+++ b/libs/vr/libpdx/service_tests.cpp
@@ -30,7 +30,6 @@
 using testing::Ref;
 using testing::Return;
 using testing::SetArgPointee;
-using testing::SetErrnoAndReturn;
 using testing::WithArg;
 using testing::WithoutArgs;
 using testing::_;
@@ -91,7 +90,7 @@
   MOCK_METHOD1(OnChannelOpen, std::shared_ptr<Channel>(Message& message));
   MOCK_METHOD2(OnChannelClose,
                void(Message& message, const std::shared_ptr<Channel>& channel));
-  MOCK_METHOD1(HandleMessage, int(Message& message));
+  MOCK_METHOD1(HandleMessage, Status<void>(Message& message));
   MOCK_METHOD1(HandleImpulse, void(Message& impulse));
   MOCK_METHOD0(OnSysPropChange, void());
   MOCK_METHOD1(DumpState, std::string(size_t max_length));
@@ -101,7 +100,9 @@
  public:
   ServiceTest() {
     auto endpoint = std::make_unique<testing::StrictMock<MockEndpoint>>();
-    EXPECT_CALL(*endpoint, SetService(_)).Times(2).WillRepeatedly(Return(0));
+    EXPECT_CALL(*endpoint, SetService(_))
+        .Times(2)
+        .WillRepeatedly(Return(Status<void>{}));
     service_ = std::make_shared<MockService>("MockSvc", std::move(endpoint));
   }
 
@@ -134,7 +135,8 @@
   }
 
   void ExpectDefaultHandleMessage() {
-    EXPECT_CALL(*endpoint(), DefaultHandleMessage(_));
+    EXPECT_CALL(*endpoint(), MessageReply(_, -EOPNOTSUPP))
+        .WillOnce(Return(Status<void>{}));
   }
 
   std::shared_ptr<MockService> service_;
@@ -222,10 +224,11 @@
   auto channel = std::make_shared<Channel>();
   EXPECT_CALL(*service_, OnChannelOpen(Ref(message))).WillOnce(Return(channel));
   EXPECT_CALL(*endpoint(), SetChannel(kTestCid, channel.get()))
-      .WillOnce(Return(0));
-  EXPECT_CALL(*endpoint(), MessageReply(&message, 0)).WillOnce(Return(0));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_CALL(*endpoint(), MessageReply(&message, 0))
+      .WillOnce(Return(Status<void>{}));
 
-  EXPECT_EQ(0, service_->Service::HandleMessage(message));
+  EXPECT_TRUE(service_->Service::HandleMessage(message));
 }
 
 TEST_F(ServiceTest, HandleMessageChannelClose) {
@@ -237,10 +240,12 @@
   Message message{info};
 
   EXPECT_CALL(*service_, OnChannelClose(Ref(message), channel));
-  EXPECT_CALL(*endpoint(), SetChannel(kTestCid, nullptr)).WillOnce(Return(0));
-  EXPECT_CALL(*endpoint(), MessageReply(&message, 0)).WillOnce(Return(0));
+  EXPECT_CALL(*endpoint(), SetChannel(kTestCid, nullptr))
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_CALL(*endpoint(), MessageReply(&message, 0))
+      .WillOnce(Return(Status<void>{}));
 
-  EXPECT_EQ(0, service_->Service::HandleMessage(message));
+  EXPECT_TRUE(service_->Service::HandleMessage(message));
 }
 
 TEST_F(ServiceTest, HandleMessageOnSysPropChange) {
@@ -250,9 +255,10 @@
   Message message{info};
 
   EXPECT_CALL(*service_, OnSysPropChange());
-  EXPECT_CALL(*endpoint(), MessageReply(&message, 0)).WillOnce(Return(0));
+  EXPECT_CALL(*endpoint(), MessageReply(&message, 0))
+      .WillOnce(Return(Status<void>{}));
 
-  EXPECT_EQ(0, service_->Service::HandleMessage(message));
+  EXPECT_TRUE(service_->Service::HandleMessage(message));
 }
 
 TEST_F(ServiceTest, HandleMessageOnDumpState) {
@@ -270,9 +276,9 @@
       WriteMessageData(&message, IoVecDataMatcher(IoVecData{kReply}), 1))
       .WillOnce(Return(kReply.size()));
   EXPECT_CALL(*endpoint(), MessageReply(&message, kReply.size()))
-      .WillOnce(Return(0));
+      .WillOnce(Return(Status<void>{}));
 
-  EXPECT_EQ(0, service_->Service::HandleMessage(message));
+  EXPECT_TRUE(service_->Service::HandleMessage(message));
 }
 
 TEST_F(ServiceTest, HandleMessageOnDumpStateTooLarge) {
@@ -291,9 +297,9 @@
       WriteMessageData(&message, IoVecDataMatcher(IoVecData{kActualReply}), 1))
       .WillOnce(Return(kActualReply.size()));
   EXPECT_CALL(*endpoint(), MessageReply(&message, kActualReply.size()))
-      .WillOnce(Return(0));
+      .WillOnce(Return(Status<void>{}));
 
-  EXPECT_EQ(0, service_->Service::HandleMessage(message));
+  EXPECT_TRUE(service_->Service::HandleMessage(message));
 }
 
 TEST_F(ServiceTest, HandleMessageOnDumpStateFail) {
@@ -310,9 +316,10 @@
       *endpoint(),
       WriteMessageData(&message, IoVecDataMatcher(IoVecData{kReply}), 1))
       .WillOnce(Return(1));
-  EXPECT_CALL(*endpoint(), MessageReply(&message, -EIO)).WillOnce(Return(0));
+  EXPECT_CALL(*endpoint(), MessageReply(&message, -EIO))
+      .WillOnce(Return(Status<void>{}));
 
-  EXPECT_EQ(0, service_->Service::HandleMessage(message));
+  EXPECT_TRUE(service_->Service::HandleMessage(message));
 }
 
 TEST_F(ServiceTest, HandleMessageCustom) {
@@ -320,10 +327,10 @@
   SetupMessageInfoAndDefaultExpectations(&info, kTestOp);
   Message message{info};
 
-  EXPECT_CALL(*endpoint(), MessageReply(&message, -ENOTSUP))
-      .WillOnce(Return(0));
+  EXPECT_CALL(*endpoint(), MessageReply(&message, -EOPNOTSUPP))
+      .WillOnce(Return(Status<void>{}));
 
-  EXPECT_EQ(0, service_->Service::HandleMessage(message));
+  EXPECT_TRUE(service_->Service::HandleMessage(message));
 }
 
 TEST_F(ServiceTest, ReplyMessageWithoutService) {
@@ -337,7 +344,7 @@
   service_.reset();
   EXPECT_TRUE(message.IsServiceExpired());
 
-  EXPECT_EQ(-EINVAL, message.Reply(12));
+  EXPECT_EQ(EINVAL, message.Reply(12).error());
 }
 
 TEST_F(ServiceTest, ReceiveAndDispatchMessage) {
@@ -345,33 +352,33 @@
   SetupMessageInfoAndDefaultExpectations(&info, kTestOp);
   ExpectDefaultHandleMessage();
 
-  auto on_receive = [&info](Message* message) {
+  auto on_receive = [&info](Message* message) -> Status<void> {
     *message = Message{info};
-    return 0;
+    return {};
   };
   EXPECT_CALL(*endpoint(), MessageReceive(_)).WillOnce(Invoke(on_receive));
-  EXPECT_CALL(*service_, HandleMessage(_)).WillOnce(Return(0));
+  EXPECT_CALL(*service_, HandleMessage(_)).WillOnce(Return(Status<void>{}));
 
-  EXPECT_EQ(0, service_->ReceiveAndDispatch());
+  EXPECT_TRUE(service_->ReceiveAndDispatch());
 }
 
 TEST_F(ServiceTest, ReceiveAndDispatchImpulse) {
   MessageInfo info;
   SetupMessageInfoAndDefaultExpectations(&info, kTestOp, true);
 
-  auto on_receive = [&info](Message* message) {
+  auto on_receive = [&info](Message* message) -> Status<void> {
     *message = Message{info};
-    return 0;
+    return {};
   };
   EXPECT_CALL(*endpoint(), MessageReceive(_)).WillOnce(Invoke(on_receive));
   EXPECT_CALL(*service_, HandleImpulse(_));
 
-  EXPECT_EQ(0, service_->ReceiveAndDispatch());
+  EXPECT_TRUE(service_->ReceiveAndDispatch());
 }
 
 TEST_F(ServiceTest, Cancel) {
-  EXPECT_CALL(*endpoint(), Cancel()).WillOnce(Return(0));
-  EXPECT_EQ(0, service_->Cancel());
+  EXPECT_CALL(*endpoint(), Cancel()).WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(service_->Cancel());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -380,85 +387,85 @@
 
 TEST_F(ServiceMessageTest, Reply) {
   EXPECT_CALL(*endpoint(), MessageReply(message_.get(), 12))
-      .WillOnce(Return(0));
+      .WillOnce(Return(Status<void>{}));
   EXPECT_FALSE(message_->replied());
-  EXPECT_EQ(0, message_->Reply(12));
+  EXPECT_TRUE(message_->Reply(12));
   EXPECT_TRUE(message_->replied());
 
-  EXPECT_EQ(-EINVAL, message_->Reply(12));  // Already replied.
+  EXPECT_EQ(EINVAL, message_->Reply(12).error());  // Already replied.
 }
 
 TEST_F(ServiceMessageTest, ReplyFail) {
   EXPECT_CALL(*endpoint(), MessageReply(message_.get(), 12))
-      .WillOnce(SetErrnoAndReturn(EIO, -1));
-  EXPECT_EQ(-EIO, message_->Reply(12));
+      .WillOnce(Return(ErrorStatus{EIO}));
+  EXPECT_EQ(EIO, message_->Reply(12).error());
 
   ExpectDefaultHandleMessage();
 }
 
 TEST_F(ServiceMessageTest, ReplyError) {
   EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -12))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->ReplyError(12));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->ReplyError(12));
 }
 
 TEST_F(ServiceMessageTest, ReplyFileDescriptor) {
   EXPECT_CALL(*endpoint(), MessageReplyFd(message_.get(), 5))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->ReplyFileDescriptor(5));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->ReplyFileDescriptor(5));
 }
 
 TEST_F(ServiceMessageTest, ReplyLocalFileHandle) {
   const int kFakeFd = 12345;
   LocalHandle handle{kFakeFd};
   EXPECT_CALL(*endpoint(), MessageReplyFd(message_.get(), kFakeFd))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(handle));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(handle));
   handle.Release();  // Make sure we do not close the fake file descriptor.
 }
 
 TEST_F(ServiceMessageTest, ReplyLocalFileHandleError) {
   LocalHandle handle{-EINVAL};
   EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -EINVAL))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(handle));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(handle));
 }
 
 TEST_F(ServiceMessageTest, ReplyBorrowedFileHandle) {
   const int kFakeFd = 12345;
   BorrowedHandle handle{kFakeFd};
   EXPECT_CALL(*endpoint(), MessageReplyFd(message_.get(), kFakeFd))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(handle));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(handle));
 }
 
 TEST_F(ServiceMessageTest, ReplyBorrowedFileHandleError) {
   BorrowedHandle handle{-EACCES};
   EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -EACCES))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(handle));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(handle));
 }
 
 TEST_F(ServiceMessageTest, ReplyRemoteFileHandle) {
   RemoteHandle handle{123};
   EXPECT_CALL(*endpoint(), MessageReply(message_.get(), handle.Get()))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(handle));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(handle));
 }
 
 TEST_F(ServiceMessageTest, ReplyRemoteFileHandleError) {
   RemoteHandle handle{-EIO};
   EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -EIO))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(handle));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(handle));
 }
 
 TEST_F(ServiceMessageTest, ReplyLocalChannelHandle) {
   LocalChannelHandle handle{nullptr, 12345};
   EXPECT_CALL(*endpoint(), MessageReplyChannelHandle(
                                message_.get(), A<const LocalChannelHandle&>()))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(handle));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(handle));
 }
 
 TEST_F(ServiceMessageTest, ReplyBorrowedChannelHandle) {
@@ -466,30 +473,30 @@
   EXPECT_CALL(*endpoint(),
               MessageReplyChannelHandle(message_.get(),
                                         A<const BorrowedChannelHandle&>()))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(handle));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(handle));
 }
 
 TEST_F(ServiceMessageTest, ReplyRemoteChannelHandle) {
   RemoteChannelHandle handle{12345};
   EXPECT_CALL(*endpoint(), MessageReplyChannelHandle(
                                message_.get(), A<const RemoteChannelHandle&>()))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(handle));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(handle));
 }
 
 TEST_F(ServiceMessageTest, ReplyStatusInt) {
   Status<int> status{123};
   EXPECT_CALL(*endpoint(), MessageReply(message_.get(), status.get()))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(status));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(status));
 }
 
 TEST_F(ServiceMessageTest, ReplyStatusError) {
   Status<int> status{ErrorStatus{EIO}};
   EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -status.error()))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->Reply(status));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->Reply(status));
 }
 
 TEST_F(ServiceMessageTest, Read) {
@@ -500,9 +507,9 @@
       *endpoint(),
       ReadMessageData(message_.get(), IoVecMatcher(kDataBuffer, kDataSize), 1))
       .WillOnce(Return(50))
-      .WillOnce(SetErrnoAndReturn(EACCES, -1));
-  EXPECT_EQ(50, message_->Read(kDataBuffer, kDataSize));
-  EXPECT_EQ(-EACCES, message_->Read(kDataBuffer, kDataSize));
+      .WillOnce(Return(ErrorStatus{EACCES}));
+  EXPECT_EQ(50u, message_->Read(kDataBuffer, kDataSize).get());
+  EXPECT_EQ(EACCES, message_->Read(kDataBuffer, kDataSize).error());
 }
 
 TEST_F(ServiceMessageTest, ReadVector) {
@@ -516,10 +523,10 @@
                   IoVecMatcher(IoVecArray{std::begin(vec), std::end(vec)}), 2))
       .WillOnce(Return(30))
       .WillOnce(Return(15))
-      .WillOnce(SetErrnoAndReturn(EBADF, -1));
-  EXPECT_EQ(30, message_->ReadVector(vec, 2));
-  EXPECT_EQ(15, message_->ReadVector(vec));
-  EXPECT_EQ(-EBADF, message_->ReadVector(vec));
+      .WillOnce(Return(ErrorStatus{EBADF}));
+  EXPECT_EQ(30u, message_->ReadVector(vec, 2).get());
+  EXPECT_EQ(15u, message_->ReadVector(vec).get());
+  EXPECT_EQ(EBADF, message_->ReadVector(vec).error());
 }
 
 TEST_F(ServiceMessageTest, Write) {
@@ -530,9 +537,9 @@
       *endpoint(),
       WriteMessageData(message_.get(), IoVecMatcher(kDataBuffer, kDataSize), 1))
       .WillOnce(Return(50))
-      .WillOnce(SetErrnoAndReturn(EBADMSG, -1));
-  EXPECT_EQ(50, message_->Write(kDataBuffer, kDataSize));
-  EXPECT_EQ(-EBADMSG, message_->Write(kDataBuffer, kDataSize));
+      .WillOnce(Return(ErrorStatus{EBADMSG}));
+  EXPECT_EQ(50u, message_->Write(kDataBuffer, kDataSize).get());
+  EXPECT_EQ(EBADMSG, message_->Write(kDataBuffer, kDataSize).error());
 }
 
 TEST_F(ServiceMessageTest, WriteVector) {
@@ -546,10 +553,10 @@
                   IoVecMatcher(IoVecArray{std::begin(vec), std::end(vec)}), 2))
       .WillOnce(Return(30))
       .WillOnce(Return(15))
-      .WillOnce(SetErrnoAndReturn(EIO, -1));
-  EXPECT_EQ(30, message_->WriteVector(vec, 2));
-  EXPECT_EQ(15, message_->WriteVector(vec));
-  EXPECT_EQ(-EIO, message_->WriteVector(vec, 2));
+      .WillOnce(Return(ErrorStatus{EIO}));
+  EXPECT_EQ(30u, message_->WriteVector(vec, 2).get());
+  EXPECT_EQ(15u, message_->WriteVector(vec).get());
+  EXPECT_EQ(EIO, message_->WriteVector(vec, 2).error());
 }
 
 TEST_F(ServiceMessageTest, PushLocalFileHandle) {
@@ -560,9 +567,9 @@
               PushFileHandle(message_.get(), Matcher<const LocalHandle&>(
                                                  FileHandleMatcher(kFakeFd))))
       .WillOnce(Return(12))
-      .WillOnce(SetErrnoAndReturn(EIO, -1));
-  EXPECT_EQ(12, message_->PushFileHandle(handle));
-  EXPECT_EQ(-EIO, message_->PushFileHandle(handle));
+      .WillOnce(Return(ErrorStatus{EIO}));
+  EXPECT_EQ(12, message_->PushFileHandle(handle).get());
+  EXPECT_EQ(EIO, message_->PushFileHandle(handle).error());
   handle.Release();  // Make sure we do not close the fake file descriptor.
 }
 
@@ -574,9 +581,9 @@
               PushFileHandle(message_.get(), Matcher<const BorrowedHandle&>(
                                                  FileHandleMatcher(kFakeFd))))
       .WillOnce(Return(13))
-      .WillOnce(SetErrnoAndReturn(EACCES, -1));
-  EXPECT_EQ(13, message_->PushFileHandle(handle));
-  EXPECT_EQ(-EACCES, message_->PushFileHandle(handle));
+      .WillOnce(Return(ErrorStatus{EACCES}));
+  EXPECT_EQ(13, message_->PushFileHandle(handle).get());
+  EXPECT_EQ(EACCES, message_->PushFileHandle(handle).error());
 }
 
 TEST_F(ServiceMessageTest, PushRemoteFileHandle) {
@@ -587,9 +594,9 @@
               PushFileHandle(message_.get(), Matcher<const RemoteHandle&>(
                                                  FileHandleMatcher(kFakeFd))))
       .WillOnce(Return(kFakeFd))
-      .WillOnce(SetErrnoAndReturn(EIO, -1));
-  EXPECT_EQ(kFakeFd, message_->PushFileHandle(handle));
-  EXPECT_EQ(-EIO, message_->PushFileHandle(handle));
+      .WillOnce(Return(ErrorStatus{EIO}));
+  EXPECT_EQ(kFakeFd, message_->PushFileHandle(handle).get());
+  EXPECT_EQ(EIO, message_->PushFileHandle(handle).error());
 }
 
 TEST_F(ServiceMessageTest, PushLocalChannelHandle) {
@@ -600,9 +607,9 @@
                                              Matcher<const LocalChannelHandle&>(
                                                  ChannelHandleMatcher(kValue))))
       .WillOnce(Return(7))
-      .WillOnce(SetErrnoAndReturn(EIO, -1));
-  EXPECT_EQ(7, message_->PushChannelHandle(handle));
-  EXPECT_EQ(-EIO, message_->PushChannelHandle(handle));
+      .WillOnce(Return(ErrorStatus{EIO}));
+  EXPECT_EQ(7, message_->PushChannelHandle(handle).get());
+  EXPECT_EQ(EIO, message_->PushChannelHandle(handle).error());
 }
 
 TEST_F(ServiceMessageTest, PushBorrowedChannelHandle) {
@@ -614,9 +621,9 @@
       PushChannelHandle(message_.get(), Matcher<const BorrowedChannelHandle&>(
                                             ChannelHandleMatcher(kValue))))
       .WillOnce(Return(8))
-      .WillOnce(SetErrnoAndReturn(EIO, -1));
-  EXPECT_EQ(8, message_->PushChannelHandle(handle));
-  EXPECT_EQ(-EIO, message_->PushChannelHandle(handle));
+      .WillOnce(Return(ErrorStatus{EIO}));
+  EXPECT_EQ(8, message_->PushChannelHandle(handle).get());
+  EXPECT_EQ(EIO, message_->PushChannelHandle(handle).error());
 }
 
 TEST_F(ServiceMessageTest, PushRemoteChannelHandle) {
@@ -628,9 +635,9 @@
       PushChannelHandle(message_.get(), Matcher<const RemoteChannelHandle&>(
                                             ChannelHandleMatcher(kValue))))
       .WillOnce(Return(kValue))
-      .WillOnce(SetErrnoAndReturn(EIO, -1));
-  EXPECT_EQ(kValue, message_->PushChannelHandle(handle));
-  EXPECT_EQ(-EIO, message_->PushChannelHandle(handle));
+      .WillOnce(Return(ErrorStatus{EIO}));
+  EXPECT_EQ(kValue, message_->PushChannelHandle(handle).get());
+  EXPECT_EQ(EIO, message_->PushChannelHandle(handle).error());
 }
 
 TEST_F(ServiceMessageTest, GetFileHandle) {
@@ -701,8 +708,8 @@
   int kClearMask = 1;
   int kSetMask = 2;
   EXPECT_CALL(*endpoint(), ModifyChannelEvents(kTestCid, kClearMask, kSetMask))
-      .WillOnce(Return(0));
-  EXPECT_EQ(0, message_->ModifyChannelEvents(kClearMask, kSetMask));
+      .WillOnce(Return(Status<void>{}));
+  EXPECT_TRUE(message_->ModifyChannelEvents(kClearMask, kSetMask));
 }
 
 TEST_F(ServiceMessageTest, PushChannelSameService) {
@@ -733,7 +740,9 @@
 TEST_F(ServiceMessageTest, PushChannelDifferentService) {
   ExpectDefaultHandleMessage();
   auto endpoint2 = std::make_unique<testing::StrictMock<MockEndpoint>>();
-  EXPECT_CALL(*endpoint2, SetService(_)).Times(2).WillRepeatedly(Return(0));
+  EXPECT_CALL(*endpoint2, SetService(_))
+      .Times(2)
+      .WillRepeatedly(Return(Status<void>{}));
   auto service2 =
       std::make_shared<MockService>("MockSvc2", std::move(endpoint2));
 
@@ -779,7 +788,9 @@
 TEST_F(ServiceMessageTest, CheckChannelDifferentService) {
   ExpectDefaultHandleMessage();
   auto endpoint2 = std::make_unique<testing::StrictMock<MockEndpoint>>();
-  EXPECT_CALL(*endpoint2, SetService(_)).Times(2).WillRepeatedly(Return(0));
+  EXPECT_CALL(*endpoint2, SetService(_))
+      .Times(2)
+      .WillRepeatedly(Return(Status<void>{}));
   auto service2 =
       std::make_shared<MockService>("MockSvc2", std::move(endpoint2));
 
diff --git a/libs/vr/libpdx/thread_local_buffer_tests.cpp b/libs/vr/libpdx/thread_local_buffer_tests.cpp
index 1747d79..6cdaf10 100644
--- a/libs/vr/libpdx/thread_local_buffer_tests.cpp
+++ b/libs/vr/libpdx/thread_local_buffer_tests.cpp
@@ -89,13 +89,13 @@
   EXPECT_NE(id1, id2);
 }
 
-// TODO(b/36456321): Fix this and enable it again.
 // Tests that thread-local buffers are allocated at the first buffer request.
-TEST(ThreadLocalBufferTest, DISABLED_InitialValue) {
+TEST(ThreadLocalBufferTest, InitialValue) {
   struct TypeTagX;
   using SendSlotX = ThreadLocalSlot<TypeTagX, kSendBufferIndex>;
 
   auto value1 = ThreadLocalBufferTest::GetSlotValue<SendSlotX>();
+  MessageBuffer<SendSlotX>::GetBuffer();
   auto value2 = ThreadLocalBufferTest::GetSlotValue<SendSlotX>();
 
   EXPECT_EQ(0U, value1);
diff --git a/libs/vr/libpdx/variant_tests.cpp b/libs/vr/libpdx/variant_tests.cpp
index c30c055..325f33f 100644
--- a/libs/vr/libpdx/variant_tests.cpp
+++ b/libs/vr/libpdx/variant_tests.cpp
@@ -368,6 +368,13 @@
   }
 
   {
+    TestType<int> i(1);
+    Variant<int, bool, float> v(i.get());
+    ASSERT_TRUE(v.is<int>());
+    EXPECT_EQ(1, std::get<int>(v));
+  }
+
+  {
     TestType<bool> b(true);
     Variant<int, bool, float> v(b.take());
     ASSERT_TRUE(v.is<bool>());
@@ -375,6 +382,13 @@
   }
 
   {
+    TestType<bool> b(true);
+    Variant<int, bool, float> v(b.get());
+    ASSERT_TRUE(v.is<bool>());
+    EXPECT_EQ(true, std::get<bool>(v));
+  }
+
+  {
     Variant<const char*> c("test");
     Variant<std::string> s(c);
     ASSERT_TRUE(s.is<std::string>());
@@ -1060,8 +1074,8 @@
   EXPECT_FALSE((detail::HasType<char, int, float, bool>::value));
   EXPECT_FALSE(detail::HasType<>::value);
 
-  EXPECT_TRUE((detail::HasTypeIgnoreRef<int&, int, float, bool>::value));
-  EXPECT_FALSE((detail::HasTypeIgnoreRef<char&, int, float, bool>::value));
+  EXPECT_TRUE((detail::HasType<int&, int, float, bool>::value));
+  EXPECT_FALSE((detail::HasType<char&, int, float, bool>::value));
 }
 
 TEST(Variant, Set) {
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 655adb8..8cfa86f 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -57,6 +57,7 @@
         "pdx_benchmarks.cpp",
     ],
     shared_libs: [
+        "libbase",
         "libchrome",
         "libcutils",
         "liblog",
diff --git a/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp b/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp
index de02401..0b658fb 100644
--- a/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp
+++ b/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp
@@ -38,6 +38,7 @@
 using android::pdx::Channel;
 using android::pdx::ClientBase;
 using android::pdx::Endpoint;
+using android::pdx::ErrorStatus;
 using android::pdx::Message;
 using android::pdx::Service;
 using android::pdx::ServiceBase;
@@ -246,7 +247,7 @@
             << message.GetChannelId();
   }
 
-  int HandleMessage(Message& message) override {
+  Status<void> HandleMessage(Message& message) override {
     ATRACE_NAME("BenchmarkService::HandleMessage");
 
     switch (message.GetOp()) {
@@ -254,30 +255,27 @@
         VLOG(1) << "BenchmarkService::HandleMessage: op=nop";
         {
           ATRACE_NAME("Reply");
-          CHECK(message.Reply(0) == 0);
+          CHECK(message.Reply(0));
         }
-        return 0;
+        return {};
 
       case BenchmarkOps::Write: {
         VLOG(1) << "BenchmarkService::HandleMessage: op=write send_length="
                 << message.GetSendLength()
                 << " receive_length=" << message.GetReceiveLength();
 
-        const ssize_t expected_length =
-            static_cast<ssize_t>(message.GetSendLength());
-        const ssize_t actual_length =
-            expected_length > 0
-                ? message.Read(send_buffer.data(), message.GetSendLength())
-                : 0;
+        Status<void> status;
+        if (message.GetSendLength())
+          status = message.ReadAll(send_buffer.data(), message.GetSendLength());
 
         {
           ATRACE_NAME("Reply");
-          if (actual_length < expected_length)
-            CHECK(message.ReplyError(EIO) == 0);
+          if (!status)
+            CHECK(message.ReplyError(status.error()));
           else
-            CHECK(message.Reply(actual_length) == 0);
+            CHECK(message.Reply(message.GetSendLength()));
         }
-        return 0;
+        return {};
       }
 
       case BenchmarkOps::Read: {
@@ -285,22 +283,20 @@
                 << message.GetSendLength()
                 << " receive_length=" << message.GetReceiveLength();
 
-        const ssize_t expected_length =
-            static_cast<ssize_t>(message.GetReceiveLength());
-        const ssize_t actual_length =
-            expected_length > 0
-                ? message.Write(receive_buffer.data(),
-                                message.GetReceiveLength())
-                : 0;
+        Status<void> status;
+        if (message.GetReceiveLength()) {
+          status = message.WriteAll(receive_buffer.data(),
+                                    message.GetReceiveLength());
+        }
 
         {
           ATRACE_NAME("Reply");
-          if (actual_length < expected_length)
-            CHECK(message.ReplyError(EIO) == 0);
+          if (!status)
+            CHECK(message.ReplyError(status.error()));
           else
-            CHECK(message.Reply(actual_length) == 0);
+            CHECK(message.Reply(message.GetReceiveLength()));
         }
-        return 0;
+        return {};
       }
 
       case BenchmarkOps::Echo: {
@@ -308,31 +304,28 @@
                 << message.GetSendLength()
                 << " receive_length=" << message.GetReceiveLength();
 
-        const ssize_t expected_length =
-            static_cast<ssize_t>(message.GetSendLength());
-        ssize_t actual_length =
-            expected_length > 0
-                ? message.Read(send_buffer.data(), message.GetSendLength())
-                : 0;
+        Status<void> status;
+        if (message.GetSendLength())
+          status = message.ReadAll(send_buffer.data(), message.GetSendLength());
 
-        if (actual_length < expected_length) {
-          CHECK(message.ReplyError(EIO) == 0);
-          return 0;
+        if (!status) {
+          CHECK(message.ReplyError(status.error()));
+          return {};
         }
 
-        actual_length =
-            expected_length > 0
-                ? message.Write(send_buffer.data(), message.GetSendLength())
-                : 0;
+        if (message.GetSendLength()) {
+          status =
+              message.WriteAll(send_buffer.data(), message.GetSendLength());
+        }
 
         {
           ATRACE_NAME("Reply");
-          if (actual_length < expected_length)
-            CHECK(message.ReplyError(EIO) == 0);
+          if (!status)
+            CHECK(message.ReplyError(status.error()));
           else
-            CHECK(message.Reply(actual_length) == 0);
+            CHECK(message.Reply(message.GetSendLength()));
         }
-        return 0;
+        return {};
       }
 
       case BenchmarkOps::Stats: {
@@ -348,7 +341,7 @@
         RemoteMethodReturn<BenchmarkRPC::Stats>(
             message, BenchmarkRPC::Stats::Return{receive_time_ns, GetClockNs(),
                                                  sched_stats_});
-        return 0;
+        return {};
       }
 
       case BenchmarkOps::WriteVector:
@@ -358,7 +351,7 @@
 
         DispatchRemoteMethod<BenchmarkRPC::WriteVector>(
             *this, &BenchmarkService::OnWriteVector, message, kMaxMessageSize);
-        return 0;
+        return {};
 
       case BenchmarkOps::EchoVector:
         VLOG(1) << "BenchmarkService::HandleMessage: op=echovec send_length="
@@ -367,11 +360,11 @@
 
         DispatchRemoteMethod<BenchmarkRPC::EchoVector>(
             *this, &BenchmarkService::OnEchoVector, message, kMaxMessageSize);
-        return 0;
+        return {};
 
       case BenchmarkOps::Quit:
         Cancel();
-        return -ESHUTDOWN;
+        return ErrorStatus{ESHUTDOWN};
 
       default:
         VLOG(1) << "BenchmarkService::HandleMessage: default case; op="
@@ -543,17 +536,17 @@
               const std::shared_ptr<BenchmarkService>& local_service) {
             SetThreadName("service" + std::to_string(service_id));
 
-            // Read the inital schedstats for this thread from procfs.
+            // Read the initial schedstats for this thread from procfs.
             local_service->UpdateSchedStats();
 
             ATRACE_NAME("BenchmarkService::Dispatch");
             while (!done) {
-              const int ret = local_service->ReceiveAndDispatch();
-              if (ret < 0) {
-                if (ret != -ESHUTDOWN) {
+              auto ret = local_service->ReceiveAndDispatch();
+              if (!ret) {
+                if (ret.error() != ESHUTDOWN) {
                   std::cerr << "Error while dispatching message on thread "
                             << thread_id << " service " << service_id << ": "
-                            << strerror(-ret) << std::endl;
+                            << ret.GetErrorMessage() << std::endl;
                 } else {
                   std::cerr << "Quitting thread " << thread_id << " service "
                             << service_id << std::endl;
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index 09eeaa0..a73ba34 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -20,6 +20,8 @@
         "service_endpoint.cpp",
     ],
     static_libs: [
+        "libcutils",
+        "libbase",
         "libpdx",
     ],
 }
@@ -41,6 +43,8 @@
         "libpdx",
     ],
     shared_libs: [
+        "libbase",
+        "libcutils",
         "liblog",
         "libutils",
     ],
diff --git a/libs/vr/libpdx_uds/channel_event_set.cpp b/libs/vr/libpdx_uds/channel_event_set.cpp
index f8baeab..ac4dea9 100644
--- a/libs/vr/libpdx_uds/channel_event_set.cpp
+++ b/libs/vr/libpdx_uds/channel_event_set.cpp
@@ -12,7 +12,7 @@
   const int flags = EFD_CLOEXEC | EFD_NONBLOCK;
   LocalHandle epoll_fd, event_fd;
 
-  if (!SetupHandle(epoll_create(1), &epoll_fd, "epoll") ||
+  if (!SetupHandle(epoll_create1(EPOLL_CLOEXEC), &epoll_fd, "epoll") ||
       !SetupHandle(eventfd(0, flags), &event_fd, "event")) {
     return;
   }
diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp
index 4cbdb94..924335f 100644
--- a/libs/vr/libpdx_uds/client_channel.cpp
+++ b/libs/vr/libpdx_uds/client_channel.cpp
@@ -67,7 +67,7 @@
   ResponseHeader<LocalHandle> response;
 };
 
-Status<void> ReadAndDiscardData(int socket_fd, size_t size) {
+Status<void> ReadAndDiscardData(const BorrowedHandle& socket_fd, size_t size) {
   while (size > 0) {
     // If there is more data to read in the message than the buffers provided
     // by the caller, read and discard the extra data from the socket.
@@ -83,9 +83,10 @@
   return ErrorStatus(EIO);
 }
 
-Status<void> SendRequest(int socket_fd, TransactionState* transaction_state,
-                         int opcode, const iovec* send_vector,
-                         size_t send_count, size_t max_recv_len) {
+Status<void> SendRequest(const BorrowedHandle& socket_fd,
+                         TransactionState* transaction_state, int opcode,
+                         const iovec* send_vector, size_t send_count,
+                         size_t max_recv_len) {
   size_t send_len = CountVectorSize(send_vector, send_count);
   InitRequest(&transaction_state->request, opcode, send_len, max_recv_len,
               false);
@@ -95,7 +96,8 @@
   return status;
 }
 
-Status<void> ReceiveResponse(int socket_fd, TransactionState* transaction_state,
+Status<void> ReceiveResponse(const BorrowedHandle& socket_fd,
+                             TransactionState* transaction_state,
                              const iovec* receive_vector, size_t receive_count,
                              size_t max_recv_len) {
   auto status = ReceiveData(socket_fd, &transaction_state->response);
@@ -164,7 +166,7 @@
 
   InitRequest(&request, opcode, length, 0, true);
   memcpy(request.impulse_payload.data(), buffer, length);
-  return SendData(channel_handle_.value(), request);
+  return SendData(BorrowedHandle{channel_handle_.value()}, request);
 }
 
 Status<int> ClientChannel::SendAndReceive(void* transaction_state, int opcode,
@@ -182,11 +184,11 @@
   auto* state = static_cast<TransactionState*>(transaction_state);
   size_t max_recv_len = CountVectorSize(receive_vector, receive_count);
 
-  auto status = SendRequest(channel_handle_.value(), state, opcode, send_vector,
-                            send_count, max_recv_len);
+  auto status = SendRequest(BorrowedHandle{channel_handle_.value()}, state,
+                            opcode, send_vector, send_count, max_recv_len);
   if (status) {
-    status = ReceiveResponse(channel_handle_.value(), state, receive_vector,
-                             receive_count, max_recv_len);
+    status = ReceiveResponse(BorrowedHandle{channel_handle_.value()}, state,
+                             receive_vector, receive_count, max_recv_len);
   }
   if (!result.PropagateError(status)) {
     const int return_code = state->response.ret_code;
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp
index f059453..323236d 100644
--- a/libs/vr/libpdx_uds/client_channel_factory.cpp
+++ b/libs/vr/libpdx_uds/client_channel_factory.cpp
@@ -111,11 +111,11 @@
         remote.sun_path);
   RequestHeader<BorrowedHandle> request;
   InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
-  status = SendData(socket_fd.Get(), request);
+  status = SendData(socket_fd.Borrow(), request);
   if (!status)
     return ErrorStatus(status.error());
   ResponseHeader<LocalHandle> response;
-  status = ReceiveData(socket_fd.Get(), &response);
+  status = ReceiveData(socket_fd.Borrow(), &response);
   if (!status)
     return ErrorStatus(status.error());
   int ref = response.ret_code;
diff --git a/libs/vr/libpdx_uds/ipc_helper.cpp b/libs/vr/libpdx_uds/ipc_helper.cpp
index ee7299e..d604f62 100644
--- a/libs/vr/libpdx_uds/ipc_helper.cpp
+++ b/libs/vr/libpdx_uds/ipc_helper.cpp
@@ -26,18 +26,19 @@
   uint32_t fd_count{0};
 };
 
-Status<void> SendPayload::Send(int socket_fd) {
+Status<void> SendPayload::Send(const BorrowedHandle& socket_fd) {
   return Send(socket_fd, nullptr);
 }
 
-Status<void> SendPayload::Send(int socket_fd, const ucred* cred) {
+Status<void> SendPayload::Send(const BorrowedHandle& socket_fd,
+                               const ucred* cred) {
   MessagePreamble preamble;
   preamble.magic = kMagicPreamble;
   preamble.data_size = buffer_.size();
   preamble.fd_count = file_handles_.size();
 
-  ssize_t ret =
-      RETRY_EINTR(send(socket_fd, &preamble, sizeof(preamble), MSG_NOSIGNAL));
+  ssize_t ret = RETRY_EINTR(
+      send(socket_fd.Get(), &preamble, sizeof(preamble), MSG_NOSIGNAL));
   if (ret < 0)
     return ErrorStatus(errno);
   if (ret != sizeof(preamble))
@@ -71,7 +72,7 @@
     }
   }
 
-  ret = RETRY_EINTR(sendmsg(socket_fd, &msg, MSG_NOSIGNAL));
+  ret = RETRY_EINTR(sendmsg(socket_fd.Get(), &msg, MSG_NOSIGNAL));
   if (ret < 0)
     return ErrorStatus(errno);
   if (static_cast<size_t>(ret) != buffer_.size())
@@ -87,7 +88,7 @@
 OutputResourceMapper* SendPayload::GetOutputResourceMapper() { return this; }
 
 // OutputResourceMapper
-FileReference SendPayload::PushFileHandle(const LocalHandle& handle) {
+Status<FileReference> SendPayload::PushFileHandle(const LocalHandle& handle) {
   if (handle) {
     const int ref = file_handles_.size();
     file_handles_.push_back(handle.Get());
@@ -97,7 +98,8 @@
   }
 }
 
-FileReference SendPayload::PushFileHandle(const BorrowedHandle& handle) {
+Status<FileReference> SendPayload::PushFileHandle(
+    const BorrowedHandle& handle) {
   if (handle) {
     const int ref = file_handles_.size();
     file_handles_.push_back(handle.Get());
@@ -107,31 +109,32 @@
   }
 }
 
-FileReference SendPayload::PushFileHandle(const RemoteHandle& handle) {
+Status<FileReference> SendPayload::PushFileHandle(const RemoteHandle& handle) {
   return handle.Get();
 }
 
-ChannelReference SendPayload::PushChannelHandle(
+Status<ChannelReference> SendPayload::PushChannelHandle(
     const LocalChannelHandle& /*handle*/) {
-  return -1;
+  return ErrorStatus{EOPNOTSUPP};
 }
-ChannelReference SendPayload::PushChannelHandle(
+Status<ChannelReference> SendPayload::PushChannelHandle(
     const BorrowedChannelHandle& /*handle*/) {
-  return -1;
+  return ErrorStatus{EOPNOTSUPP};
 }
-ChannelReference SendPayload::PushChannelHandle(
+Status<ChannelReference> SendPayload::PushChannelHandle(
     const RemoteChannelHandle& /*handle*/) {
-  return -1;
+  return ErrorStatus{EOPNOTSUPP};
 }
 
-Status<void> ReceivePayload::Receive(int socket_fd) {
+Status<void> ReceivePayload::Receive(const BorrowedHandle& socket_fd) {
   return Receive(socket_fd, nullptr);
 }
 
-Status<void> ReceivePayload::Receive(int socket_fd, ucred* cred) {
+Status<void> ReceivePayload::Receive(const BorrowedHandle& socket_fd,
+                                     ucred* cred) {
   MessagePreamble preamble;
-  ssize_t ret =
-      RETRY_EINTR(recv(socket_fd, &preamble, sizeof(preamble), MSG_WAITALL));
+  ssize_t ret = RETRY_EINTR(
+      recv(socket_fd.Get(), &preamble, sizeof(preamble), MSG_WAITALL));
   if (ret < 0)
     return ErrorStatus(errno);
   else if (ret == 0)
@@ -156,7 +159,7 @@
     msg.msg_control = alloca(msg.msg_controllen);
   }
 
-  ret = RETRY_EINTR(recvmsg(socket_fd, &msg, MSG_WAITALL));
+  ret = RETRY_EINTR(recvmsg(socket_fd.Get(), &msg, MSG_WAITALL));
   if (ret < 0)
     return ErrorStatus(errno);
   else if (ret == 0)
@@ -218,8 +221,10 @@
   return false;
 }
 
-Status<void> SendData(int socket_fd, const void* data, size_t size) {
-  ssize_t size_written = RETRY_EINTR(send(socket_fd, data, size, MSG_NOSIGNAL));
+Status<void> SendData(const BorrowedHandle& socket_fd, const void* data,
+                      size_t size) {
+  ssize_t size_written =
+      RETRY_EINTR(send(socket_fd.Get(), data, size, MSG_NOSIGNAL));
   if (size_written < 0)
     return ErrorStatus(errno);
   if (static_cast<size_t>(size_written) != size)
@@ -227,11 +232,13 @@
   return {};
 }
 
-Status<void> SendDataVector(int socket_fd, const iovec* data, size_t count) {
+Status<void> SendDataVector(const BorrowedHandle& socket_fd, const iovec* data,
+                            size_t count) {
   msghdr msg = {};
   msg.msg_iov = const_cast<iovec*>(data);
   msg.msg_iovlen = count;
-  ssize_t size_written = RETRY_EINTR(sendmsg(socket_fd, &msg, MSG_NOSIGNAL));
+  ssize_t size_written =
+      RETRY_EINTR(sendmsg(socket_fd.Get(), &msg, MSG_NOSIGNAL));
   if (size_written < 0)
     return ErrorStatus(errno);
   if (static_cast<size_t>(size_written) != CountVectorSize(data, count))
@@ -239,8 +246,10 @@
   return {};
 }
 
-Status<void> ReceiveData(int socket_fd, void* data, size_t size) {
-  ssize_t size_read = RETRY_EINTR(recv(socket_fd, data, size, MSG_WAITALL));
+Status<void> ReceiveData(const BorrowedHandle& socket_fd, void* data,
+                         size_t size) {
+  ssize_t size_read =
+      RETRY_EINTR(recv(socket_fd.Get(), data, size, MSG_WAITALL));
   if (size_read < 0)
     return ErrorStatus(errno);
   else if (size_read == 0)
@@ -250,11 +259,12 @@
   return {};
 }
 
-Status<void> ReceiveDataVector(int socket_fd, const iovec* data, size_t count) {
+Status<void> ReceiveDataVector(const BorrowedHandle& socket_fd,
+                               const iovec* data, size_t count) {
   msghdr msg = {};
   msg.msg_iov = const_cast<iovec*>(data);
   msg.msg_iovlen = count;
-  ssize_t size_read = RETRY_EINTR(recvmsg(socket_fd, &msg, MSG_WAITALL));
+  ssize_t size_read = RETRY_EINTR(recvmsg(socket_fd.Get(), &msg, MSG_WAITALL));
   if (size_read < 0)
     return ErrorStatus(errno);
   else if (size_read == 0)
diff --git a/libs/vr/libpdx_uds/private/uds/ipc_helper.h b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
index 00f3490..82950a2 100644
--- a/libs/vr/libpdx_uds/private/uds/ipc_helper.h
+++ b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
@@ -25,21 +25,22 @@
 
 class SendPayload : public MessageWriter, public OutputResourceMapper {
  public:
-  Status<void> Send(int socket_fd);
-  Status<void> Send(int socket_fd, const ucred* cred);
+  Status<void> Send(const BorrowedHandle& socket_fd);
+  Status<void> Send(const BorrowedHandle& socket_fd, const ucred* cred);
 
   // MessageWriter
   void* GetNextWriteBufferSection(size_t size) override;
   OutputResourceMapper* GetOutputResourceMapper() override;
 
   // OutputResourceMapper
-  FileReference PushFileHandle(const LocalHandle& handle) override;
-  FileReference PushFileHandle(const BorrowedHandle& handle) override;
-  FileReference PushFileHandle(const RemoteHandle& handle) override;
-  ChannelReference PushChannelHandle(const LocalChannelHandle& handle) override;
-  ChannelReference PushChannelHandle(
+  Status<FileReference> PushFileHandle(const LocalHandle& handle) override;
+  Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override;
+  Status<FileReference> PushFileHandle(const RemoteHandle& handle) override;
+  Status<ChannelReference> PushChannelHandle(
+      const LocalChannelHandle& handle) override;
+  Status<ChannelReference> PushChannelHandle(
       const BorrowedChannelHandle& handle) override;
-  ChannelReference PushChannelHandle(
+  Status<ChannelReference> PushChannelHandle(
       const RemoteChannelHandle& handle) override;
 
  private:
@@ -49,8 +50,8 @@
 
 class ReceivePayload : public MessageReader, public InputResourceMapper {
  public:
-  Status<void> Receive(int socket_fd);
-  Status<void> Receive(int socket_fd, ucred* cred);
+  Status<void> Receive(const BorrowedHandle& socket_fd);
+  Status<void> Receive(const BorrowedHandle& socket_fd, ucred* cred);
 
   // MessageReader
   BufferSection GetNextReadBufferSection() override;
@@ -110,25 +111,27 @@
 };
 
 template <typename T>
-inline Status<void> SendData(int socket_fd, const T& data) {
+inline Status<void> SendData(const BorrowedHandle& socket_fd, const T& data) {
   SendPayload payload;
   rpc::Serialize(data, &payload);
   return payload.Send(socket_fd);
 }
 
 template <typename FileHandleType>
-inline Status<void> SendData(int socket_fd,
+inline Status<void> SendData(const BorrowedHandle& socket_fd,
                              const RequestHeader<FileHandleType>& request) {
   SendPayload payload;
   rpc::Serialize(request, &payload);
   return payload.Send(socket_fd, &request.cred);
 }
 
-Status<void> SendData(int socket_fd, const void* data, size_t size);
-Status<void> SendDataVector(int socket_fd, const iovec* data, size_t count);
+Status<void> SendData(const BorrowedHandle& socket_fd, const void* data,
+                      size_t size);
+Status<void> SendDataVector(const BorrowedHandle& socket_fd, const iovec* data,
+                            size_t count);
 
 template <typename T>
-inline Status<void> ReceiveData(int socket_fd, T* data) {
+inline Status<void> ReceiveData(const BorrowedHandle& socket_fd, T* data) {
   ReceivePayload payload;
   Status<void> status = payload.Receive(socket_fd);
   if (status && rpc::Deserialize(data, &payload) != rpc::ErrorCode::NO_ERROR)
@@ -137,7 +140,7 @@
 }
 
 template <typename FileHandleType>
-inline Status<void> ReceiveData(int socket_fd,
+inline Status<void> ReceiveData(const BorrowedHandle& socket_fd,
                                 RequestHeader<FileHandleType>* request) {
   ReceivePayload payload;
   Status<void> status = payload.Receive(socket_fd, &request->cred);
@@ -146,8 +149,10 @@
   return status;
 }
 
-Status<void> ReceiveData(int socket_fd, void* data, size_t size);
-Status<void> ReceiveDataVector(int socket_fd, const iovec* data, size_t count);
+Status<void> ReceiveData(const BorrowedHandle& socket_fd, void* data,
+                         size_t size);
+Status<void> ReceiveDataVector(const BorrowedHandle& socket_fd,
+                               const iovec* data, size_t count);
 
 size_t CountVectorSize(const iovec* data, size_t count);
 void InitRequest(android::pdx::uds::RequestHeader<BorrowedHandle>* request,
diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
index 3ec8519..f747abc 100644
--- a/libs/vr/libpdx_uds/private/uds/service_endpoint.h
+++ b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
@@ -39,41 +39,40 @@
   ~Endpoint() override = default;
 
   uint32_t GetIpcTag() const override { return kIpcTag; }
-  int SetService(Service* service) override;
-  int SetChannel(int channel_id, Channel* channel) override;
-  int CloseChannel(int channel_id) override;
-  int ModifyChannelEvents(int channel_id, int clear_mask,
-                          int set_mask) override;
+  Status<void> SetService(Service* service) override;
+  Status<void> SetChannel(int channel_id, Channel* channel) override;
+  Status<void> CloseChannel(int channel_id) override;
+  Status<void> ModifyChannelEvents(int channel_id, int clear_mask,
+                                   int set_mask) override;
   Status<RemoteChannelHandle> PushChannel(Message* message, int flags,
                                           Channel* channel,
                                           int* channel_id) override;
   Status<int> CheckChannel(const Message* message, ChannelReference ref,
                            Channel** channel) override;
-  int DefaultHandleMessage(const MessageInfo& info) override;
-  int MessageReceive(Message* message) override;
-  int MessageReply(Message* message, int return_code) override;
-  int MessageReplyFd(Message* message, unsigned int push_fd) override;
-  int MessageReplyChannelHandle(Message* message,
-                                const LocalChannelHandle& handle) override;
-  int MessageReplyChannelHandle(Message* message,
-                                const BorrowedChannelHandle& handle) override;
-  int MessageReplyChannelHandle(Message* message,
-                                const RemoteChannelHandle& handle) override;
-  ssize_t ReadMessageData(Message* message, const iovec* vector,
-                          size_t vector_length) override;
-  ssize_t WriteMessageData(Message* message, const iovec* vector,
-                           size_t vector_length) override;
-  FileReference PushFileHandle(Message* message,
-                               const LocalHandle& handle) override;
-  FileReference PushFileHandle(Message* message,
-                               const BorrowedHandle& handle) override;
-  FileReference PushFileHandle(Message* message,
-                               const RemoteHandle& handle) override;
-  ChannelReference PushChannelHandle(Message* message,
-                                     const LocalChannelHandle& handle) override;
-  ChannelReference PushChannelHandle(
+  Status<void> MessageReceive(Message* message) override;
+  Status<void> MessageReply(Message* message, int return_code) override;
+  Status<void> MessageReplyFd(Message* message, unsigned int push_fd) override;
+  Status<void> MessageReplyChannelHandle(
+      Message* message, const LocalChannelHandle& handle) override;
+  Status<void> MessageReplyChannelHandle(
       Message* message, const BorrowedChannelHandle& handle) override;
-  ChannelReference PushChannelHandle(
+  Status<void> MessageReplyChannelHandle(
+      Message* message, const RemoteChannelHandle& handle) override;
+  Status<size_t> ReadMessageData(Message* message, const iovec* vector,
+                                 size_t vector_length) override;
+  Status<size_t> WriteMessageData(Message* message, const iovec* vector,
+                                  size_t vector_length) override;
+  Status<FileReference> PushFileHandle(Message* message,
+                                       const LocalHandle& handle) override;
+  Status<FileReference> PushFileHandle(Message* message,
+                                       const BorrowedHandle& handle) override;
+  Status<FileReference> PushFileHandle(Message* message,
+                                       const RemoteHandle& handle) override;
+  Status<ChannelReference> PushChannelHandle(
+      Message* message, const LocalChannelHandle& handle) override;
+  Status<ChannelReference> PushChannelHandle(
+      Message* message, const BorrowedChannelHandle& handle) override;
+  Status<ChannelReference> PushChannelHandle(
       Message* message, const RemoteChannelHandle& handle) override;
   LocalHandle GetFileHandle(Message* message, FileReference ref) const override;
   LocalChannelHandle GetChannelHandle(Message* message,
@@ -82,15 +81,22 @@
   void* AllocateMessageState() override;
   void FreeMessageState(void* state) override;
 
-  int Cancel() override;
+  Status<void> Cancel() override;
 
   // Open an endpoint at the given path.
   // Second parameter is unused for UDS, but we have it here for compatibility
   // in signature with servicefs::Endpoint::Create().
+  // This method uses |endpoint_path| as a relative path to endpoint socket
+  // created by init process.
   static std::unique_ptr<Endpoint> Create(const std::string& endpoint_path,
                                           mode_t /*unused_mode*/ = kDefaultMode,
                                           bool blocking = kDefaultBlocking);
 
+  // Helper method to create an endpoint at the given UDS socket path. This
+  // method physically creates and binds a socket at that path.
+  static std::unique_ptr<Endpoint> CreateAndBindSocket(
+      const std::string& endpoint_path, bool blocking = kDefaultBlocking);
+
   int epoll_fd() const { return epoll_fd_.Get(); }
 
  private:
@@ -101,7 +107,8 @@
   };
 
   // This class must be instantiated using Create() static methods above.
-  Endpoint(const std::string& endpoint_path, bool blocking);
+  Endpoint(const std::string& endpoint_path, bool blocking,
+           bool use_init_socket_fd = true);
 
   Endpoint(const Endpoint&) = delete;
   void operator=(const Endpoint&) = delete;
@@ -110,18 +117,20 @@
     return next_message_id_.fetch_add(1, std::memory_order_relaxed);
   }
 
-  void BuildCloseMessage(int channel_id, Message* message);
+  void BuildCloseMessage(int32_t channel_id, Message* message);
 
   Status<void> AcceptConnection(Message* message);
-  Status<void> ReceiveMessageForChannel(int channel_id, Message* message);
+  Status<void> ReceiveMessageForChannel(const BorrowedHandle& channel_fd,
+                                        Message* message);
   Status<void> OnNewChannel(LocalHandle channel_fd);
-  Status<ChannelData*> OnNewChannelLocked(LocalHandle channel_fd,
-                                          Channel* channel_state);
-  int CloseChannelLocked(int channel_id);
-  Status<void> ReenableEpollEvent(int fd);
-  Channel* GetChannelState(int channel_id);
-  int GetChannelSocketFd(int channel_id);
-  int GetChannelEventFd(int channel_id);
+  Status<std::pair<int32_t, ChannelData*>> OnNewChannelLocked(
+      LocalHandle channel_fd, Channel* channel_state);
+  Status<void> CloseChannelLocked(int32_t channel_id);
+  Status<void> ReenableEpollEvent(const BorrowedHandle& channel_fd);
+  Channel* GetChannelState(int32_t channel_id);
+  BorrowedHandle GetChannelSocketFd(int32_t channel_id);
+  BorrowedHandle GetChannelEventFd(int32_t channel_id);
+  int32_t GetChannelId(const BorrowedHandle& channel_fd);
 
   std::string endpoint_path_;
   bool is_blocking_;
@@ -130,7 +139,9 @@
   LocalHandle epoll_fd_;
 
   mutable std::mutex channel_mutex_;
-  std::map<int, ChannelData> channels_;
+  std::map<int32_t, ChannelData> channels_;
+  std::map<int, int32_t> channel_fd_to_id_;
+  int32_t last_channel_id_{0};
 
   Service* service_{nullptr};
   std::atomic<uint32_t> next_message_id_;
diff --git a/libs/vr/libpdx_uds/remote_method_tests.cpp b/libs/vr/libpdx_uds/remote_method_tests.cpp
index 9050500..3109753 100644
--- a/libs/vr/libpdx_uds/remote_method_tests.cpp
+++ b/libs/vr/libpdx_uds/remote_method_tests.cpp
@@ -342,87 +342,87 @@
 // Test service that encodes/decodes messages from clients.
 class TestService : public ServiceBase<TestService> {
  public:
-  int HandleMessage(Message& message) override {
+  Status<void> HandleMessage(Message& message) override {
     switch (message.GetOp()) {
       case TestInterface::Add::Opcode:
         DispatchRemoteMethod<TestInterface::Add>(*this, &TestService::OnAdd,
                                                  message);
-        return 0;
+        return {};
 
       case TestInterface::Foo::Opcode:
         DispatchRemoteMethod<TestInterface::Foo>(*this, &TestService::OnFoo,
                                                  message);
-        return 0;
+        return {};
 
       case TestInterface::Concatenate::Opcode:
         DispatchRemoteMethod<TestInterface::Concatenate>(
             *this, &TestService::OnConcatenate, message);
-        return 0;
+        return {};
 
       case TestInterface::SumVector::Opcode:
         DispatchRemoteMethod<TestInterface::SumVector>(
             *this, &TestService::OnSumVector, message);
-        return 0;
+        return {};
 
       case TestInterface::StringLength::Opcode:
         DispatchRemoteMethod<TestInterface::StringLength>(
             *this, &TestService::OnStringLength, message);
-        return 0;
+        return {};
 
       case TestInterface::SendTestType::Opcode:
         DispatchRemoteMethod<TestInterface::SendTestType>(
             *this, &TestService::OnSendTestType, message);
-        return 0;
+        return {};
 
       case TestInterface::SendVector::Opcode:
         DispatchRemoteMethod<TestInterface::SendVector>(
             *this, &TestService::OnSendVector, message);
-        return 0;
+        return {};
 
       case TestInterface::Rot13::Opcode:
         DispatchRemoteMethod<TestInterface::Rot13>(*this, &TestService::OnRot13,
                                                    message);
-        return 0;
+        return {};
 
       case TestInterface::NoArgs::Opcode:
         DispatchRemoteMethod<TestInterface::NoArgs>(
             *this, &TestService::OnNoArgs, message);
-        return 0;
+        return {};
 
       case TestInterface::SendFile::Opcode:
         DispatchRemoteMethod<TestInterface::SendFile>(
             *this, &TestService::OnSendFile, message);
-        return 0;
+        return {};
 
       case TestInterface::GetFile::Opcode:
         DispatchRemoteMethod<TestInterface::GetFile>(
             *this, &TestService::OnGetFile, message);
-        return 0;
+        return {};
 
       case TestInterface::GetTestFdType::Opcode:
         DispatchRemoteMethod<TestInterface::GetTestFdType>(
             *this, &TestService::OnGetTestFdType, message);
-        return 0;
+        return {};
 
       case TestInterface::OpenFiles::Opcode:
         DispatchRemoteMethod<TestInterface::OpenFiles>(
             *this, &TestService::OnOpenFiles, message);
-        return 0;
+        return {};
 
       case TestInterface::ReadFile::Opcode:
         DispatchRemoteMethod<TestInterface::ReadFile>(
             *this, &TestService::OnReadFile, message);
-        return 0;
+        return {};
 
       case TestInterface::PushChannel::Opcode:
         DispatchRemoteMethod<TestInterface::PushChannel>(
             *this, &TestService::OnPushChannel, message);
-        return 0;
+        return {};
 
       case TestInterface::Positive::Opcode:
         DispatchRemoteMethod<TestInterface::Positive>(
             *this, &TestService::OnPositive, message);
-        return 0;
+        return {};
 
       default:
         return Service::DefaultHandleMessage(message);
@@ -433,7 +433,8 @@
   friend BASE;
 
   TestService()
-      : BASE("TestService", Endpoint::Create(TestInterface::kClientPath)) {}
+      : BASE("TestService",
+             Endpoint::CreateAndBindSocket(TestInterface::kClientPath)) {}
 
   int OnAdd(Message&, int a, int b) { return a + b; }
 
diff --git a/libs/vr/libpdx_uds/service_dispatcher.cpp b/libs/vr/libpdx_uds/service_dispatcher.cpp
index fa98f26..2c52578 100644
--- a/libs/vr/libpdx_uds/service_dispatcher.cpp
+++ b/libs/vr/libpdx_uds/service_dispatcher.cpp
@@ -30,7 +30,7 @@
     return;
   }
 
-  epoll_fd_.Reset(epoll_create(1));  // Size arg is ignored, but must be > 0.
+  epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
   if (!epoll_fd_) {
     ALOGE("Failed to create epoll fd because: %s\n", strerror(errno));
     return;
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 7bf753d..65fd59f 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -7,6 +7,9 @@
 #include <sys/un.h>
 #include <algorithm>  // std::min
 
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <cutils/sockets.h>
 #include <pdx/service.h>
 #include <uds/channel_manager.h>
 #include <uds/client_channel_factory.h>
@@ -19,6 +22,7 @@
 using android::pdx::BorrowedChannelHandle;
 using android::pdx::BorrowedHandle;
 using android::pdx::ChannelReference;
+using android::pdx::ErrorStatus;
 using android::pdx::FileReference;
 using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
@@ -51,14 +55,14 @@
     return true;
   }
 
-  FileReference PushFileHandle(BorrowedHandle handle) {
+  Status<FileReference> PushFileHandle(BorrowedHandle handle) {
     if (!handle)
       return handle.Get();
     response.file_descriptors.push_back(std::move(handle));
     return response.file_descriptors.size() - 1;
   }
 
-  ChannelReference PushChannelHandle(BorrowedChannelHandle handle) {
+  Status<ChannelReference> PushChannelHandle(BorrowedChannelHandle handle) {
     if (!handle)
       return handle.value();
 
@@ -70,14 +74,14 @@
       response.channels.push_back(std::move(channel_info));
       return response.channels.size() - 1;
     } else {
-      return -1;
+      return ErrorStatus{EINVAL};
     }
   }
 
-  ChannelReference PushChannelHandle(BorrowedHandle data_fd,
-                                     BorrowedHandle event_fd) {
+  Status<ChannelReference> PushChannelHandle(BorrowedHandle data_fd,
+                                             BorrowedHandle event_fd) {
     if (!data_fd || !event_fd)
-      return -1;
+      return ErrorStatus{EINVAL};
     ChannelInfo<BorrowedHandle> channel_info;
     channel_info.data_fd = std::move(data_fd);
     channel_info.event_fd = std::move(event_fd);
@@ -85,8 +89,8 @@
     return response.channels.size() - 1;
   }
 
-  ssize_t WriteData(const iovec* vector, size_t vector_length) {
-    ssize_t size = 0;
+  Status<size_t> WriteData(const iovec* vector, size_t vector_length) {
+    size_t size = 0;
     for (size_t i = 0; i < vector_length; i++) {
       const auto* data = reinterpret_cast<const uint8_t*>(vector[i].iov_base);
       response_data.insert(response_data.end(), data, data + vector[i].iov_len);
@@ -95,9 +99,9 @@
     return size;
   }
 
-  ssize_t ReadData(const iovec* vector, size_t vector_length) {
+  Status<size_t> ReadData(const iovec* vector, size_t vector_length) {
     size_t size_remaining = request_data.size() - request_data_read_pos;
-    ssize_t size = 0;
+    size_t size = 0;
     for (size_t i = 0; i < vector_length && size_remaining > 0; i++) {
       size_t size_to_copy = std::min(size_remaining, vector[i].iov_len);
       memcpy(vector[i].iov_base, request_data.data() + request_data_read_pos,
@@ -123,43 +127,50 @@
 namespace pdx {
 namespace uds {
 
-Endpoint::Endpoint(const std::string& endpoint_path, bool blocking)
+Endpoint::Endpoint(const std::string& endpoint_path, bool blocking,
+                   bool use_init_socket_fd)
     : endpoint_path_{ClientChannelFactory::GetEndpointPath(endpoint_path)},
       is_blocking_{blocking} {
-  LocalHandle fd{socket(AF_UNIX, SOCK_STREAM, 0)};
-  if (!fd) {
-    ALOGE("Endpoint::Endpoint: Failed to create socket: %s", strerror(errno));
-    return;
-  }
+  LocalHandle fd;
+  if (use_init_socket_fd) {
+    // Cut off the /dev/socket/ prefix from the full socket path and use the
+    // resulting "name" to retrieve the file descriptor for the socket created
+    // by the init process.
+    constexpr char prefix[] = "/dev/socket/";
+    CHECK(android::base::StartsWith(endpoint_path_, prefix))
+        << "Endpoint::Endpoint: Socket name '" << endpoint_path_
+        << "' must begin with '" << prefix << "'";
+    std::string socket_name = endpoint_path_.substr(sizeof(prefix) - 1);
+    fd.Reset(android_get_control_socket(socket_name.c_str()));
+    CHECK(fd.IsValid())
+        << "Endpoint::Endpoint: Unable to obtain the control socket fd for '"
+        << socket_name << "'";
+    fcntl(fd.Get(), F_SETFD, FD_CLOEXEC);
+  } else {
+    fd.Reset(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0));
+    CHECK(fd.IsValid()) << "Endpoint::Endpoint: Failed to create socket: "
+                        << strerror(errno);
 
-  sockaddr_un local;
-  local.sun_family = AF_UNIX;
-  strncpy(local.sun_path, endpoint_path_.c_str(), sizeof(local.sun_path));
-  local.sun_path[sizeof(local.sun_path) - 1] = '\0';
+    sockaddr_un local;
+    local.sun_family = AF_UNIX;
+    strncpy(local.sun_path, endpoint_path_.c_str(), sizeof(local.sun_path));
+    local.sun_path[sizeof(local.sun_path) - 1] = '\0';
 
-  unlink(local.sun_path);
-  if (bind(fd.Get(), (struct sockaddr*)&local, sizeof(local)) == -1) {
-    ALOGE("Endpoint::Endpoint: bind error: %s", strerror(errno));
-    return;
+    unlink(local.sun_path);
+    int ret =
+        bind(fd.Get(), reinterpret_cast<sockaddr*>(&local), sizeof(local));
+    CHECK_EQ(ret, 0) << "Endpoint::Endpoint: bind error: " << strerror(errno);
   }
-  if (listen(fd.Get(), kMaxBackLogForSocketListen) == -1) {
-    ALOGE("Endpoint::Endpoint: listen error: %s", strerror(errno));
-    return;
-  }
+  CHECK_EQ(listen(fd.Get(), kMaxBackLogForSocketListen), 0)
+      << "Endpoint::Endpoint: listen error: " << strerror(errno);
 
   cancel_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
-  if (!cancel_event_fd_) {
-    ALOGE("Endpoint::Endpoint: Failed to create event fd: %s\n",
-          strerror(errno));
-    return;
-  }
+  CHECK(cancel_event_fd_.IsValid())
+      << "Endpoint::Endpoint: Failed to create event fd: " << strerror(errno);
 
-  epoll_fd_.Reset(epoll_create(1));  // Size arg is ignored, but must be > 0.
-  if (!epoll_fd_) {
-    ALOGE("Endpoint::Endpoint: Failed to create epoll fd: %s\n",
-          strerror(errno));
-    return;
-  }
+  epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
+  CHECK(epoll_fd_.IsValid())
+      << "Endpoint::Endpoint: Failed to create epoll fd: " << strerror(errno);
 
   epoll_event socket_event;
   socket_event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
@@ -169,16 +180,16 @@
   cancel_event.events = EPOLLIN;
   cancel_event.data.fd = cancel_event_fd_.Get();
 
-  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, fd.Get(), &socket_event) < 0 ||
-      epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, cancel_event_fd_.Get(),
-                &cancel_event) < 0) {
-    ALOGE("Endpoint::Endpoint: Failed to add event fd to epoll fd: %s\n",
-          strerror(errno));
-    cancel_event_fd_.Close();
-    epoll_fd_.Close();
-  } else {
-    socket_fd_ = std::move(fd);
-  }
+  int ret = epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, fd.Get(), &socket_event);
+  CHECK_EQ(ret, 0)
+      << "Endpoint::Endpoint: Failed to add socket fd to epoll fd: "
+      << strerror(errno);
+  ret = epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, cancel_event_fd_.Get(),
+                  &cancel_event);
+  CHECK_EQ(ret, 0)
+      << "Endpoint::Endpoint: Failed to add cancel event fd to epoll fd: "
+      << strerror(errno);
+  socket_fd_ = std::move(fd);
 }
 
 void* Endpoint::AllocateMessageState() { return new MessageState; }
@@ -190,8 +201,9 @@
 Status<void> Endpoint::AcceptConnection(Message* message) {
   sockaddr_un remote;
   socklen_t addrlen = sizeof(remote);
-  LocalHandle channel_fd{
-      accept(socket_fd_.Get(), reinterpret_cast<sockaddr*>(&remote), &addrlen)};
+  LocalHandle channel_fd{accept4(socket_fd_.Get(),
+                                 reinterpret_cast<sockaddr*>(&remote), &addrlen,
+                                 SOCK_CLOEXEC)};
   if (!channel_fd) {
     ALOGE("Endpoint::AcceptConnection: failed to accept connection: %s",
           strerror(errno));
@@ -208,24 +220,26 @@
     return ErrorStatus(errno);
   }
 
-  auto status = ReceiveMessageForChannel(channel_fd.Get(), message);
+  // Borrow the channel handle before we pass (move) it into OnNewChannel().
+  BorrowedHandle borrowed_channel_handle = channel_fd.Borrow();
+  auto status = OnNewChannel(std::move(channel_fd));
   if (status)
-    status = OnNewChannel(std::move(channel_fd));
+    status = ReceiveMessageForChannel(borrowed_channel_handle, message);
   return status;
 }
 
-int Endpoint::SetService(Service* service) {
+Status<void> Endpoint::SetService(Service* service) {
   service_ = service;
-  return 0;
+  return {};
 }
 
-int Endpoint::SetChannel(int channel_id, Channel* channel) {
+Status<void> Endpoint::SetChannel(int channel_id, Channel* channel) {
   std::lock_guard<std::mutex> autolock(channel_mutex_);
   auto channel_data = channels_.find(channel_id);
   if (channel_data == channels_.end())
-    return -EINVAL;
+    return ErrorStatus{EINVAL};
   channel_data->second.channel_state = channel;
-  return 0;
+  return {};
 }
 
 Status<void> Endpoint::OnNewChannel(LocalHandle channel_fd) {
@@ -235,7 +249,7 @@
   return status;
 }
 
-Status<Endpoint::ChannelData*> Endpoint::OnNewChannelLocked(
+Status<std::pair<int32_t, Endpoint::ChannelData*>> Endpoint::OnNewChannelLocked(
     LocalHandle channel_fd, Channel* channel_state) {
   epoll_event event;
   event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
@@ -247,19 +261,28 @@
     return ErrorStatus(errno);
   }
   ChannelData channel_data;
-  const int channel_id = channel_fd.Get();
   channel_data.event_set.AddDataFd(channel_fd);
   channel_data.data_fd = std::move(channel_fd);
   channel_data.channel_state = channel_state;
-  auto pair = channels_.emplace(channel_id, std::move(channel_data));
-  return &pair.first->second;
+  for (;;) {
+    // Try new channel IDs until we find one which is not already in the map.
+    if (last_channel_id_++ == std::numeric_limits<int32_t>::max())
+      last_channel_id_ = 1;
+    auto iter = channels_.lower_bound(last_channel_id_);
+    if (iter == channels_.end() || iter->first != last_channel_id_) {
+      channel_fd_to_id_.emplace(channel_data.data_fd.Get(), last_channel_id_);
+      iter = channels_.emplace_hint(iter, last_channel_id_,
+                                    std::move(channel_data));
+      return std::make_pair(last_channel_id_, &iter->second);
+    }
+  }
 }
 
-Status<void> Endpoint::ReenableEpollEvent(int fd) {
+Status<void> Endpoint::ReenableEpollEvent(const BorrowedHandle& fd) {
   epoll_event event;
   event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
-  event.data.fd = fd;
-  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_MOD, fd, &event) < 0) {
+  event.data.fd = fd.Get();
+  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_MOD, fd.Get(), &event) < 0) {
     ALOGE(
         "Endpoint::ReenableEpollEvent: Failed to re-enable channel to "
         "endpoint: %s\n",
@@ -269,44 +292,48 @@
   return {};
 }
 
-int Endpoint::CloseChannel(int channel_id) {
+Status<void> Endpoint::CloseChannel(int channel_id) {
   std::lock_guard<std::mutex> autolock(channel_mutex_);
   return CloseChannelLocked(channel_id);
 }
 
-int Endpoint::CloseChannelLocked(int channel_id) {
+Status<void> Endpoint::CloseChannelLocked(int32_t channel_id) {
   ALOGD_IF(TRACE, "Endpoint::CloseChannelLocked: channel_id=%d", channel_id);
 
-  auto channel_data = channels_.find(channel_id);
-  if (channel_data == channels_.end())
-    return -EINVAL;
+  auto iter = channels_.find(channel_id);
+  if (iter == channels_.end())
+    return ErrorStatus{EINVAL};
 
-  int ret = 0;
+  int channel_fd = iter->second.data_fd.Get();
+  Status<void> status;
   epoll_event dummy;  // See BUGS in man 2 epoll_ctl.
-  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, channel_id, &dummy) < 0) {
-    ret = -errno;
+  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, channel_fd, &dummy) < 0) {
+    status.SetError(errno);
     ALOGE(
         "Endpoint::CloseChannelLocked: Failed to remove channel from endpoint: "
         "%s\n",
         strerror(errno));
+  } else {
+    status.SetValue();
   }
 
-  channels_.erase(channel_data);
-  return ret;
+  channel_fd_to_id_.erase(channel_fd);
+  channels_.erase(iter);
+  return status;
 }
 
-int Endpoint::ModifyChannelEvents(int channel_id, int clear_mask,
-                                  int set_mask) {
+Status<void> Endpoint::ModifyChannelEvents(int channel_id, int clear_mask,
+                                           int set_mask) {
   std::lock_guard<std::mutex> autolock(channel_mutex_);
 
   auto search = channels_.find(channel_id);
   if (search != channels_.end()) {
     auto& channel_data = search->second;
     channel_data.event_set.ModifyEvents(clear_mask, set_mask);
-    return 0;
+    return {};
   }
 
-  return -EINVAL;
+  return ErrorStatus{EINVAL};
 }
 
 Status<RemoteChannelHandle> Endpoint::PushChannel(Message* message,
@@ -314,7 +341,7 @@
                                                   Channel* channel,
                                                   int* channel_id) {
   int channel_pair[2] = {};
-  if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel_pair) == -1) {
+  if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, channel_pair) == -1) {
     ALOGE("Endpoint::PushChannel: Failed to create a socket pair: %s",
           strerror(errno));
     return ErrorStatus(errno);
@@ -334,20 +361,22 @@
   }
 
   std::lock_guard<std::mutex> autolock(channel_mutex_);
-  *channel_id = local_socket.Get();
   auto channel_data = OnNewChannelLocked(std::move(local_socket), channel);
   if (!channel_data)
-    return ErrorStatus(channel_data.error());
+    return channel_data.error_status();
+  *channel_id = channel_data.get().first;
 
   // Flags are ignored for now.
   // TODO(xiaohuit): Implement those.
 
   auto* state = static_cast<MessageState*>(message->GetState());
-  ChannelReference ref = state->PushChannelHandle(
+  Status<ChannelReference> ref = state->PushChannelHandle(
       remote_socket.Borrow(),
-      channel_data.get()->event_set.event_fd().Borrow());
+      channel_data.get().second->event_set.event_fd().Borrow());
+  if (!ref)
+    return ref.error_status();
   state->sockets_to_close.push_back(std::move(remote_socket));
-  return RemoteChannelHandle{ref};
+  return RemoteChannelHandle{ref.get()};
 }
 
 Status<int> Endpoint::CheckChannel(const Message* /*message*/,
@@ -357,39 +386,42 @@
   return ErrorStatus(EFAULT);
 }
 
-int Endpoint::DefaultHandleMessage(const MessageInfo& /* info */) {
-  ALOGE(
-      "Endpoint::CheckChannel: Not implemented! Endpoint DefaultHandleMessage "
-      "does nothing!");
-  return 0;
-}
-
-Channel* Endpoint::GetChannelState(int channel_id) {
+Channel* Endpoint::GetChannelState(int32_t channel_id) {
   std::lock_guard<std::mutex> autolock(channel_mutex_);
   auto channel_data = channels_.find(channel_id);
   return (channel_data != channels_.end()) ? channel_data->second.channel_state
                                            : nullptr;
 }
 
-int Endpoint::GetChannelSocketFd(int channel_id) {
+BorrowedHandle Endpoint::GetChannelSocketFd(int32_t channel_id) {
   std::lock_guard<std::mutex> autolock(channel_mutex_);
+  BorrowedHandle handle;
   auto channel_data = channels_.find(channel_id);
-  return (channel_data != channels_.end()) ? channel_data->second.data_fd.Get()
-                                           : -1;
+  if (channel_data != channels_.end())
+    handle = channel_data->second.data_fd.Borrow();
+  return handle;
 }
 
-int Endpoint::GetChannelEventFd(int channel_id) {
+BorrowedHandle Endpoint::GetChannelEventFd(int32_t channel_id) {
   std::lock_guard<std::mutex> autolock(channel_mutex_);
+  BorrowedHandle handle;
   auto channel_data = channels_.find(channel_id);
-  return (channel_data != channels_.end())
-             ? channel_data->second.event_set.event_fd().Get()
-             : -1;
+  if (channel_data != channels_.end())
+    handle = channel_data->second.event_set.event_fd().Borrow();
+  return handle;
 }
 
-Status<void> Endpoint::ReceiveMessageForChannel(int channel_id,
-                                                Message* message) {
+int32_t Endpoint::GetChannelId(const BorrowedHandle& channel_fd) {
+  std::lock_guard<std::mutex> autolock(channel_mutex_);
+  auto iter = channel_fd_to_id_.find(channel_fd.Get());
+  return (iter != channel_fd_to_id_.end()) ? iter->second : -1;
+}
+
+Status<void> Endpoint::ReceiveMessageForChannel(
+    const BorrowedHandle& channel_fd, Message* message) {
   RequestHeader<LocalHandle> request;
-  auto status = ReceiveData(channel_id, &request);
+  int32_t channel_id = GetChannelId(channel_fd);
+  auto status = ReceiveData(channel_fd.Borrow(), &request);
   if (!status) {
     if (status.error() == ESHUTDOWN) {
       BuildCloseMessage(channel_id, message);
@@ -425,12 +457,12 @@
   state->request = std::move(request);
   if (request.send_len > 0 && !request.is_impulse) {
     state->request_data.resize(request.send_len);
-    status = ReceiveData(channel_id, state->request_data.data(),
+    status = ReceiveData(channel_fd, state->request_data.data(),
                          state->request_data.size());
   }
 
   if (status && request.is_impulse)
-    status = ReenableEpollEvent(channel_id);
+    status = ReenableEpollEvent(channel_fd);
 
   if (!status) {
     if (status.error() == ESHUTDOWN) {
@@ -445,7 +477,7 @@
   return status;
 }
 
-void Endpoint::BuildCloseMessage(int channel_id, Message* message) {
+void Endpoint::BuildCloseMessage(int32_t channel_id, Message* message) {
   ALOGD_IF(TRACE, "Endpoint::BuildCloseMessage: channel_id=%d", channel_id);
   MessageInfo info;
   info.pid = -1;
@@ -464,7 +496,7 @@
   *message = Message{info};
 }
 
-int Endpoint::MessageReceive(Message* message) {
+Status<void> Endpoint::MessageReceive(Message* message) {
   // Receive at most one event from the epoll set. This should prevent multiple
   // dispatch threads from attempting to handle messages on the same socket at
   // the same time.
@@ -474,40 +506,36 @@
   if (count < 0) {
     ALOGE("Endpoint::MessageReceive: Failed to wait for epoll events: %s\n",
           strerror(errno));
-    return -errno;
+    return ErrorStatus{errno};
   } else if (count == 0) {
-    return -ETIMEDOUT;
+    return ErrorStatus{ETIMEDOUT};
   }
 
   if (event.data.fd == cancel_event_fd_.Get()) {
-    return -ESHUTDOWN;
+    return ErrorStatus{ESHUTDOWN};
   }
 
   if (event.data.fd == socket_fd_.Get()) {
     auto status = AcceptConnection(message);
     if (!status)
-      return -status.error();
-    status = ReenableEpollEvent(socket_fd_.Get());
-    return status ? 0 : -status.error();
+      return status;
+    return ReenableEpollEvent(socket_fd_.Borrow());
   }
 
-  int channel_id = event.data.fd;
+  BorrowedHandle channel_fd{event.data.fd};
   if (event.events & (EPOLLRDHUP | EPOLLHUP)) {
-    BuildCloseMessage(channel_id, message);
-    return 0;
+    BuildCloseMessage(GetChannelId(channel_fd), message);
+    return {};
   }
 
-  auto status = ReceiveMessageForChannel(channel_id, message);
-  if (!status)
-    return -status.error();
-  return 0;
+  return ReceiveMessageForChannel(channel_fd, message);
 }
 
-int Endpoint::MessageReply(Message* message, int return_code) {
-  const int channel_id = message->GetChannelId();
-  const int channel_socket = GetChannelSocketFd(channel_id);
-  if (channel_socket < 0)
-    return -EBADF;
+Status<void> Endpoint::MessageReply(Message* message, int return_code) {
+  const int32_t channel_id = message->GetChannelId();
+  auto channel_socket = GetChannelSocketFd(channel_id);
+  if (!channel_socket)
+    return ErrorStatus{EBADF};
 
   auto* state = static_cast<MessageState*>(message->GetState());
   switch (message->GetOp()) {
@@ -515,12 +543,16 @@
       return CloseChannel(channel_id);
 
     case opcodes::CHANNEL_OPEN:
-      if (return_code < 0)
+      if (return_code < 0) {
         return CloseChannel(channel_id);
-      // Reply with the event fd.
-      return_code = state->PushFileHandle(
-          BorrowedHandle{GetChannelEventFd(channel_socket)});
-      state->response_data.clear();  // Just in case...
+      } else {
+        // Reply with the event fd.
+        auto push_status = state->PushFileHandle(GetChannelEventFd(channel_id));
+        state->response_data.clear();  // Just in case...
+        if (!push_status)
+          return push_status.error_status();
+        return_code = push_status.get();
+      }
       break;
   }
 
@@ -535,76 +567,82 @@
   if (status)
     status = ReenableEpollEvent(channel_socket);
 
-  return status ? 0 : -status.error();
+  return status;
 }
 
-int Endpoint::MessageReplyFd(Message* message, unsigned int push_fd) {
+Status<void> Endpoint::MessageReplyFd(Message* message, unsigned int push_fd) {
   auto* state = static_cast<MessageState*>(message->GetState());
   auto ref = state->PushFileHandle(BorrowedHandle{static_cast<int>(push_fd)});
-  return MessageReply(message, ref);
+  if (!ref)
+    return ref.error_status();
+  return MessageReply(message, ref.get());
 }
 
-int Endpoint::MessageReplyChannelHandle(Message* message,
-                                        const LocalChannelHandle& handle) {
+Status<void> Endpoint::MessageReplyChannelHandle(
+    Message* message, const LocalChannelHandle& handle) {
   auto* state = static_cast<MessageState*>(message->GetState());
   auto ref = state->PushChannelHandle(handle.Borrow());
-  return MessageReply(message, ref);
+  if (!ref)
+    return ref.error_status();
+  return MessageReply(message, ref.get());
 }
 
-int Endpoint::MessageReplyChannelHandle(Message* message,
-                                        const BorrowedChannelHandle& handle) {
+Status<void> Endpoint::MessageReplyChannelHandle(
+    Message* message, const BorrowedChannelHandle& handle) {
   auto* state = static_cast<MessageState*>(message->GetState());
   auto ref = state->PushChannelHandle(handle.Duplicate());
-  return MessageReply(message, ref);
+  if (!ref)
+    return ref.error_status();
+  return MessageReply(message, ref.get());
 }
 
-int Endpoint::MessageReplyChannelHandle(Message* message,
-                                        const RemoteChannelHandle& handle) {
+Status<void> Endpoint::MessageReplyChannelHandle(
+    Message* message, const RemoteChannelHandle& handle) {
   return MessageReply(message, handle.value());
 }
 
-ssize_t Endpoint::ReadMessageData(Message* message, const iovec* vector,
-                                  size_t vector_length) {
+Status<size_t> Endpoint::ReadMessageData(Message* message, const iovec* vector,
+                                         size_t vector_length) {
   auto* state = static_cast<MessageState*>(message->GetState());
   return state->ReadData(vector, vector_length);
 }
 
-ssize_t Endpoint::WriteMessageData(Message* message, const iovec* vector,
-                                   size_t vector_length) {
+Status<size_t> Endpoint::WriteMessageData(Message* message, const iovec* vector,
+                                          size_t vector_length) {
   auto* state = static_cast<MessageState*>(message->GetState());
   return state->WriteData(vector, vector_length);
 }
 
-FileReference Endpoint::PushFileHandle(Message* message,
-                                       const LocalHandle& handle) {
+Status<FileReference> Endpoint::PushFileHandle(Message* message,
+                                               const LocalHandle& handle) {
   auto* state = static_cast<MessageState*>(message->GetState());
   return state->PushFileHandle(handle.Borrow());
 }
 
-FileReference Endpoint::PushFileHandle(Message* message,
-                                       const BorrowedHandle& handle) {
+Status<FileReference> Endpoint::PushFileHandle(Message* message,
+                                               const BorrowedHandle& handle) {
   auto* state = static_cast<MessageState*>(message->GetState());
   return state->PushFileHandle(handle.Duplicate());
 }
 
-FileReference Endpoint::PushFileHandle(Message* /*message*/,
-                                       const RemoteHandle& handle) {
+Status<FileReference> Endpoint::PushFileHandle(Message* /*message*/,
+                                               const RemoteHandle& handle) {
   return handle.Get();
 }
 
-ChannelReference Endpoint::PushChannelHandle(Message* message,
-                                             const LocalChannelHandle& handle) {
+Status<ChannelReference> Endpoint::PushChannelHandle(
+    Message* message, const LocalChannelHandle& handle) {
   auto* state = static_cast<MessageState*>(message->GetState());
   return state->PushChannelHandle(handle.Borrow());
 }
 
-ChannelReference Endpoint::PushChannelHandle(
+Status<ChannelReference> Endpoint::PushChannelHandle(
     Message* message, const BorrowedChannelHandle& handle) {
   auto* state = static_cast<MessageState*>(message->GetState());
   return state->PushChannelHandle(handle.Duplicate());
 }
 
-ChannelReference Endpoint::PushChannelHandle(
+Status<ChannelReference> Endpoint::PushChannelHandle(
     Message* /*message*/, const RemoteChannelHandle& handle) {
   return handle.value();
 }
@@ -624,8 +662,10 @@
   return handle;
 }
 
-int Endpoint::Cancel() {
-  return (eventfd_write(cancel_event_fd_.Get(), 1) < 0) ? -errno : 0;
+Status<void> Endpoint::Cancel() {
+  if (eventfd_write(cancel_event_fd_.Get(), 1) < 0)
+    return ErrorStatus{errno};
+  return {};
 }
 
 std::unique_ptr<Endpoint> Endpoint::Create(const std::string& endpoint_path,
@@ -634,6 +674,12 @@
   return std::unique_ptr<Endpoint>(new Endpoint(endpoint_path, blocking));
 }
 
+std::unique_ptr<Endpoint> Endpoint::CreateAndBindSocket(
+    const std::string& endpoint_path, bool blocking) {
+  return std::unique_ptr<Endpoint>(
+      new Endpoint(endpoint_path, blocking, false));
+}
+
 }  // namespace uds
 }  // namespace pdx
 }  // namespace android
diff --git a/libs/vr/libpdx_uds/service_framework_tests.cpp b/libs/vr/libpdx_uds/service_framework_tests.cpp
index 9e31e82..2943239 100644
--- a/libs/vr/libpdx_uds/service_framework_tests.cpp
+++ b/libs/vr/libpdx_uds/service_framework_tests.cpp
@@ -119,106 +119,106 @@
     }
   }
 
-  int HandleMessage(Message& message) override {
+  Status<void> HandleMessage(Message& message) override {
     switch (message.GetOp()) {
       case TEST_OP_GET_SERVICE_ID:
-        REPLY_MESSAGE_RETURN(message, service_id_, 0);
+        REPLY_MESSAGE_RETURN(message, service_id_, {});
 
       // Set the test channel to the TestChannel for the current channel. Other
       // messages can use this to perform tests.
       case TEST_OP_SET_TEST_CHANNEL:
         test_channel_ = message.GetChannel<TestChannel>();
-        REPLY_MESSAGE_RETURN(message, 0, 0);
+        REPLY_MESSAGE_RETURN(message, 0, {});
 
       // Return the channel id for the current channel.
       case TEST_OP_GET_THIS_CHANNEL_ID:
-        REPLY_MESSAGE_RETURN(message, message.GetChannelId(), 0);
+        REPLY_MESSAGE_RETURN(message, message.GetChannelId(), {});
 
       // Return the channel id for the test channel.
       case TEST_OP_GET_TEST_CHANNEL_ID:
         if (test_channel_)
-          REPLY_MESSAGE_RETURN(message, test_channel_->channel_id(), 0);
+          REPLY_MESSAGE_RETURN(message, test_channel_->channel_id(), {});
         else
-          REPLY_ERROR_RETURN(message, ENOENT, 0);
+          REPLY_ERROR_RETURN(message, ENOENT, {});
 
       // Test check channel feature.
       case TEST_OP_CHECK_CHANNEL_ID: {
         ChannelReference ref = 0;
-        if (message.Read(&ref, sizeof(ref)) < static_cast<ssize_t>(sizeof(ref)))
-          REPLY_ERROR_RETURN(message, EIO, 0);
+        if (!message.ReadAll(&ref, sizeof(ref)))
+          REPLY_ERROR_RETURN(message, EIO, {});
 
         const Status<int> ret = message.CheckChannel<TestChannel>(ref, nullptr);
-        REPLY_MESSAGE_RETURN(message, ret, 0);
+        REPLY_MESSAGE_RETURN(message, ret, {});
       }
 
       case TEST_OP_CHECK_CHANNEL_OBJECT: {
         std::shared_ptr<TestChannel> channel;
         ChannelReference ref = 0;
-        if (message.Read(&ref, sizeof(ref)) < static_cast<ssize_t>(sizeof(ref)))
-          REPLY_ERROR_RETURN(message, EIO, 0);
+        if (!message.ReadAll(&ref, sizeof(ref)))
+          REPLY_ERROR_RETURN(message, EIO, {});
 
         const Status<int> ret =
             message.CheckChannel<TestChannel>(ref, &channel);
         if (!ret)
-          REPLY_MESSAGE_RETURN(message, ret, 0);
+          REPLY_MESSAGE_RETURN(message, ret, {});
 
         if (channel != nullptr)
-          REPLY_MESSAGE_RETURN(message, channel->channel_id(), 0);
+          REPLY_MESSAGE_RETURN(message, channel->channel_id(), {});
         else
-          REPLY_ERROR_RETURN(message, ENODATA, 0);
+          REPLY_ERROR_RETURN(message, ENODATA, {});
       }
 
       case TEST_OP_CHECK_CHANNEL_FROM_OTHER_SERVICE: {
         ChannelReference ref = 0;
-        if (message.Read(&ref, sizeof(ref)) < static_cast<ssize_t>(sizeof(ref)))
-          REPLY_ERROR_RETURN(message, EIO, 0);
+        if (!message.ReadAll(&ref, sizeof(ref)))
+          REPLY_ERROR_RETURN(message, EIO, {});
 
         const Status<int> ret = message.CheckChannel<TestChannel>(
             other_service_.get(), ref, nullptr);
-        REPLY_MESSAGE_RETURN(message, ret, 0);
+        REPLY_MESSAGE_RETURN(message, ret, {});
       }
 
       case TEST_OP_GET_NEW_CHANNEL: {
         auto channel = std::make_shared<TestChannel>(-1);
         Status<RemoteChannelHandle> channel_handle =
             message.PushChannel(0, channel, &channel->channel_id_);
-        REPLY_MESSAGE_RETURN(message, channel_handle, 0);
+        REPLY_MESSAGE_RETURN(message, channel_handle, {});
       }
 
       case TEST_OP_GET_NEW_CHANNEL_FROM_OTHER_SERVICE: {
         if (!other_service_)
-          REPLY_ERROR_RETURN(message, EINVAL, 0);
+          REPLY_ERROR_RETURN(message, EINVAL, {});
 
         auto channel = std::make_shared<TestChannel>(-1);
         Status<RemoteChannelHandle> channel_handle = message.PushChannel(
             other_service_.get(), 0, channel, &channel->channel_id_);
-        REPLY_MESSAGE_RETURN(message, channel_handle, 0);
+        REPLY_MESSAGE_RETURN(message, channel_handle, {});
       }
 
       case TEST_OP_GET_THIS_PROCESS_ID:
-        REPLY_MESSAGE_RETURN(message, message.GetProcessId(), 0);
+        REPLY_MESSAGE_RETURN(message, message.GetProcessId(), {});
 
       case TEST_OP_GET_THIS_THREAD_ID:
-        REPLY_MESSAGE_RETURN(message, message.GetThreadId(), 0);
+        REPLY_MESSAGE_RETURN(message, message.GetThreadId(), {});
 
       case TEST_OP_GET_THIS_EUID:
-        REPLY_MESSAGE_RETURN(message, message.GetEffectiveUserId(), 0);
+        REPLY_MESSAGE_RETURN(message, message.GetEffectiveUserId(), {});
 
       case TEST_OP_GET_THIS_EGID:
-        REPLY_MESSAGE_RETURN(message, message.GetEffectiveGroupId(), 0);
+        REPLY_MESSAGE_RETURN(message, message.GetEffectiveGroupId(), {});
 
       case TEST_OP_POLLIN_FROM_SERVICE:
         REPLY_MESSAGE_RETURN(message, message.ModifyChannelEvents(0, EPOLLIN),
-                             0);
+                             {});
 
       case TEST_OP_SEND_LARGE_DATA_RETURN_SUM: {
         std::array<int, kLargeDataSize> data_array;
-        ssize_t size_to_read = data_array.size() * sizeof(int);
-        ssize_t read = message.Read(data_array.data(), size_to_read);
-        if (read < size_to_read)
-          REPLY_ERROR_RETURN(message, EIO, 0);
+        size_t size_to_read = data_array.size() * sizeof(int);
+        if (!message.ReadAll(data_array.data(), size_to_read)) {
+          REPLY_ERROR_RETURN(message, EIO, {});
+        }
         int sum = std::accumulate(data_array.begin(), data_array.end(), 0);
-        REPLY_MESSAGE_RETURN(message, sum, 0);
+        REPLY_MESSAGE_RETURN(message, sum, {});
       }
 
       default:
@@ -245,7 +245,7 @@
   TestService(const std::string& name,
               const std::shared_ptr<TestService>& other_service, bool blocking)
       : BASE(std::string("TestService") + name,
-             Endpoint::Create(kTestServicePath + name, blocking)),
+             Endpoint::CreateAndBindSocket(kTestServicePath + name, blocking)),
         other_service_(other_service),
         service_id_(service_counter_++) {}
 
@@ -300,7 +300,7 @@
   // Returns the channel id of the channel.
   int CheckChannelIdArgument(BorrowedChannelHandle channel) {
     Transaction trans{*this};
-    ChannelReference ref = trans.PushChannelHandle(channel);
+    ChannelReference ref = trans.PushChannelHandle(channel).get();
     return ReturnStatusOrError(trans.Send<int>(TEST_OP_CHECK_CHANNEL_ID, &ref,
                                                sizeof(ref), nullptr, 0));
   }
@@ -309,7 +309,7 @@
   // Returns the channel id of the channel exercising the context pointer.
   int CheckChannelObjectArgument(BorrowedChannelHandle channel) {
     Transaction trans{*this};
-    ChannelReference ref = trans.PushChannelHandle(channel);
+    ChannelReference ref = trans.PushChannelHandle(channel).get();
     return ReturnStatusOrError(trans.Send<int>(TEST_OP_CHECK_CHANNEL_OBJECT,
                                                &ref, sizeof(ref), nullptr, 0));
   }
@@ -318,7 +318,7 @@
   // Returns 0 on success.
   int CheckChannelFromOtherService(BorrowedChannelHandle channel) {
     Transaction trans{*this};
-    ChannelReference ref = trans.PushChannelHandle(channel);
+    ChannelReference ref = trans.PushChannelHandle(channel).get();
     return ReturnStatusOrError(
         trans.Send<int>(TEST_OP_CHECK_CHANNEL_FROM_OTHER_SERVICE, &ref,
                         sizeof(ref), nullptr, 0));
diff --git a/libs/vr/libposepredictor/include/polynomial_predictor.h b/libs/vr/libposepredictor/include/polynomial_predictor.h
index 762afd3..4b8d51b 100644
--- a/libs/vr/libposepredictor/include/polynomial_predictor.h
+++ b/libs/vr/libposepredictor/include/polynomial_predictor.h
@@ -19,7 +19,7 @@
  public:
   PolynomialPosePredictor(real regularization = 1e-9)
       : BufferedPredictor(TrainingWindow), regularization_(regularization) {
-    static_assert(PolynomialDegree + 1 >= TrainingWindow,
+    static_assert(TrainingWindow >= PolynomialDegree + 1,
                   "Underconstrained polynomial regressor");
   }
 
diff --git a/libs/vr/libposepredictor/predictor.cpp b/libs/vr/libposepredictor/predictor.cpp
index 4d2eafd..beba156 100644
--- a/libs/vr/libposepredictor/predictor.cpp
+++ b/libs/vr/libposepredictor/predictor.cpp
@@ -5,7 +5,7 @@
 namespace posepredictor {
 
 vec3 Predictor::AngularVelocity(const quat& a, const quat& b, real delta_time) {
-  const auto delta_q = b.inverse() * a;
+  const auto delta_q = a.inverse() * b;
   // Check that delta_q.w() == 1, Eigen doesn't respect this convention. If
   // delta_q.w() == -1, we'll get the opposite velocity.
   return 2.0 * (delta_q.w() < 0 ? static_cast<vec3>(-delta_q.vec()) : delta_q.vec()) / delta_time;
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 3f79a7b..0daab64 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -47,7 +47,6 @@
 ]
 
 sharedLibraries = [
-    "android.dvr.composer@1.0",
     "android.hardware.graphics.allocator@2.0",
     "android.hardware.graphics.composer@2.1",
     "libbinder",
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index e07901d..49b6f09 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -32,12 +32,12 @@
 namespace dvr {
 
 void DisplayManager::SetNotificationsPending(bool pending) {
-  int ret = service_->ModifyChannelEvents(channel_id_, pending ? 0 : POLLIN,
-                                          pending ? POLLIN : 0);
-  ALOGE_IF(ret < 0,
+  auto status = service_->ModifyChannelEvents(channel_id_, pending ? 0 : POLLIN,
+                                              pending ? POLLIN : 0);
+  ALOGE_IF(!status,
            "DisplayManager::SetNotificationPending: Failed to modify channel "
            "events: %s",
-           strerror(-ret));
+           status.GetErrorMessage().c_str());
 }
 
 DisplayManagerService::DisplayManagerService(
@@ -68,24 +68,24 @@
     display_manager_ = nullptr;
 }
 
-int DisplayManagerService::HandleMessage(pdx::Message& message) {
+pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) {
   auto channel = std::static_pointer_cast<DisplayManager>(message.GetChannel());
 
   switch (message.GetOp()) {
     case DisplayManagerRPC::GetSurfaceList::Opcode:
       DispatchRemoteMethod<DisplayManagerRPC::GetSurfaceList>(
           *this, &DisplayManagerService::OnGetSurfaceList, message);
-      return 0;
+      return {};
 
     case DisplayManagerRPC::UpdateSurfaces::Opcode:
       DispatchRemoteMethod<DisplayManagerRPC::UpdateSurfaces>(
           *this, &DisplayManagerService::OnUpdateSurfaces, message);
-      return 0;
+      return {};
 
   case DisplayManagerRPC::SetupPoseBuffer::Opcode:
       DispatchRemoteMethod<DisplayManagerRPC::SetupPoseBuffer>(
           *this, &DisplayManagerService::OnSetupPoseBuffer, message);
-      return 0;
+      return {};
 
     default:
       return Service::DefaultHandleMessage(message);
@@ -189,7 +189,7 @@
 }
 
 pdx::BorrowedChannelHandle DisplayManagerService::OnSetupPoseBuffer(
-    pdx::Message& message, size_t extended_region_size, int usage) {
+    pdx::Message& /*message*/, size_t extended_region_size, int usage) {
   return display_service_->SetupPoseBuffer(extended_region_size, usage);
 }
 
diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h
index 19098c2..80324fd 100644
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ b/libs/vr/libvrflinger/display_manager_service.h
@@ -42,7 +42,7 @@
   std::shared_ptr<pdx::Channel> OnChannelOpen(pdx::Message& message) override;
   void OnChannelClose(pdx::Message& message,
                       const std::shared_ptr<pdx::Channel>& channel) override;
-  int HandleMessage(pdx::Message& message) override;
+  pdx::Status<void> HandleMessage(pdx::Message& message) override;
 
  private:
   friend BASE;
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index c079187..bb8613c 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -65,39 +65,39 @@
 // First-level dispatch for display service messages. Directly handles messages
 // that are independent of the display surface (metrics, creation) and routes
 // surface-specific messages to the per-instance handlers.
-int DisplayService::HandleMessage(pdx::Message& message) {
+pdx::Status<void> DisplayService::HandleMessage(pdx::Message& message) {
   auto channel = message.GetChannel<SurfaceChannel>();
 
   switch (message.GetOp()) {
     case DisplayRPC::GetMetrics::Opcode:
       DispatchRemoteMethod<DisplayRPC::GetMetrics>(
           *this, &DisplayService::OnGetMetrics, message);
-      return 0;
+      return {};
 
     case DisplayRPC::GetEdsCapture::Opcode:
       DispatchRemoteMethod<DisplayRPC::GetEdsCapture>(
           *this, &DisplayService::OnGetEdsCapture, message);
-      return 0;
+      return {};
 
     case DisplayRPC::CreateSurface::Opcode:
       DispatchRemoteMethod<DisplayRPC::CreateSurface>(
           *this, &DisplayService::OnCreateSurface, message);
-      return 0;
+      return {};
 
     case DisplayRPC::SetViewerParams::Opcode:
       DispatchRemoteMethod<DisplayRPC::SetViewerParams>(
           *this, &DisplayService::OnSetViewerParams, message);
-      return 0;
+      return {};
 
     case DisplayRPC::GetPoseBuffer::Opcode:
       DispatchRemoteMethod<DisplayRPC::GetPoseBuffer>(
           *this, &DisplayService::OnGetPoseBuffer, message);
-      return 0;
+      return {};
 
     case DisplayRPC::IsVrAppRunning::Opcode:
       DispatchRemoteMethod<DisplayRPC::IsVrAppRunning>(
           *this, &DisplayService::IsVrAppRunning, message);
-      return 0;
+      return {};
 
     // Direct the surface specific messages to the surface instance.
     case DisplayRPC::CreateBufferQueue::Opcode:
@@ -265,7 +265,7 @@
 
 // Calls the message handler for the DisplaySurface associated with this
 // channel.
-int DisplayService::HandleSurfaceMessage(pdx::Message& message) {
+pdx::Status<void> DisplayService::HandleSurfaceMessage(pdx::Message& message) {
   auto surface = std::static_pointer_cast<SurfaceChannel>(message.GetChannel());
   ALOGW_IF(!surface,
            "DisplayService::HandleSurfaceMessage: surface is nullptr!");
@@ -273,7 +273,7 @@
   if (surface)
     return surface->HandleMessage(message);
   else
-    REPLY_ERROR_RETURN(message, EINVAL, 0);
+    REPLY_ERROR_RETURN(message, EINVAL, {});
 }
 
 std::shared_ptr<DisplaySurface> DisplayService::GetDisplaySurface(
@@ -361,10 +361,10 @@
 }
 
 int DisplayService::IsVrAppRunning(pdx::Message& message) {
-  bool visible = true;
+  bool visible = false;
   ForEachDisplaySurface([&visible](const std::shared_ptr<DisplaySurface>& surface) {
-    if (surface->client_z_order() == 0 && !surface->IsVisible())
-      visible = false;
+    if (surface->client_z_order() == 0 && surface->IsVisible())
+      visible = true;
   });
 
   REPLY_SUCCESS_RETURN(message, visible, 0);
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 8e96172..da80a84 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -27,7 +27,7 @@
 
   void OnChannelClose(pdx::Message& message,
                       const std::shared_ptr<pdx::Channel>& channel) override;
-  int HandleMessage(pdx::Message& message) override;
+  pdx::Status<void> HandleMessage(pdx::Message& message) override;
 
   std::shared_ptr<DisplaySurface> GetDisplaySurface(int surface_id) const;
   std::vector<std::shared_ptr<DisplaySurface>> GetDisplaySurfaces() const;
@@ -94,7 +94,7 @@
   // the display manager should be notified.
   void NotifyDisplayConfigurationUpdate();
 
-  int HandleSurfaceMessage(pdx::Message& message);
+  pdx::Status<void> HandleSurfaceMessage(pdx::Message& message);
 
   DisplayService(const DisplayService&) = delete;
   void operator=(const DisplayService&) = delete;
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 66e9925..a7220fe 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -206,7 +206,7 @@
   return !acquired_buffers_.IsEmpty();
 }
 
-int DisplaySurface::HandleMessage(pdx::Message& message) {
+pdx::Status<void> DisplaySurface::HandleMessage(pdx::Message& message) {
   switch (message.GetOp()) {
     case DisplayRPC::SetAttributes::Opcode:
       DispatchRemoteMethod<DisplayRPC::SetAttributes>(
@@ -227,7 +227,7 @@
       return SurfaceChannel::HandleMessage(message);
   }
 
-  return 0;
+  return {};
 }
 
 int DisplaySurface::OnClientSetAttributes(
@@ -301,7 +301,7 @@
     pdx::Message& message) {
   if (flags_ & DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION) {
     ALOGE(
-        "DisplaySurface::OnCreateVideoMeshSurface: system distorion is "
+        "DisplaySurface::OnCreateVideoMeshSurface: system distortion is "
         "disabled on this display surface, cannot create VideoMeshSurface on "
         "top of it.");
     REPLY_ERROR_RETURN(message, EINVAL, {});
@@ -309,22 +309,21 @@
 
   int channel_id;
   auto status = message.PushChannel(0, nullptr, &channel_id);
-
   if (!status) {
     ALOGE(
         "DisplaySurface::OnCreateVideoMeshSurface: failed to push channel: %s",
         status.GetErrorMessage().c_str());
-    REPLY_ERROR_RETURN(message, ENOMEM, {});
+    REPLY_ERROR_RETURN(message, status.error(), {});
   }
 
   auto surface = std::make_shared<VideoMeshSurface>(service(), channel_id);
-  const int ret = service()->SetChannel(channel_id, surface);
-  if (ret < 0) {
+  auto channel_status = service()->SetChannel(channel_id, surface);
+  if (!channel_status) {
     ALOGE(
         "DisplaySurface::OnCreateVideoMeshSurface: failed to set new video "
         "mesh surface channel: %s",
-        strerror(-ret));
-    REPLY_ERROR_RETURN(message, ENOMEM, {});
+        channel_status.GetErrorMessage().c_str());
+    REPLY_ERROR_RETURN(message, channel_status.error(), {});
   }
 
   {
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index d31a3a9..2e4cf75 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -106,7 +106,7 @@
 
   // Dispatches display surface messages to the appropriate handlers. This
   // handler runs on the displayd message dispatch thread.
-  int HandleMessage(pdx::Message& message) override;
+  pdx::Status<void> HandleMessage(pdx::Message& message) override;
 
   // Sets display surface's client-controlled attributes.
   int OnClientSetAttributes(pdx::Message& message,
diff --git a/libs/vr/libvrflinger/screenshot_service.cpp b/libs/vr/libvrflinger/screenshot_service.cpp
index fd1c582..d14d588 100644
--- a/libs/vr/libvrflinger/screenshot_service.cpp
+++ b/libs/vr/libvrflinger/screenshot_service.cpp
@@ -19,17 +19,17 @@
 
 ScreenshotService::~ScreenshotService() { instance_ = nullptr; }
 
-int ScreenshotService::HandleMessage(pdx::Message& message) {
+pdx::Status<void> ScreenshotService::HandleMessage(pdx::Message& message) {
   switch (message.GetOp()) {
     case DisplayScreenshotRPC::GetFormat::Opcode:
       DispatchRemoteMethod<DisplayScreenshotRPC::GetFormat>(
           *this, &ScreenshotService::OnGetFormat, message);
-      return 0;
+      return {};
 
     case DisplayScreenshotRPC::TakeScreenshot::Opcode:
       DispatchRemoteMethod<DisplayScreenshotRPC::TakeScreenshot>(
           *this, &ScreenshotService::OnTakeScreenshot, message);
-      return 0;
+      return {};
 
     default:
       return Service::HandleMessage(message);
diff --git a/libs/vr/libvrflinger/screenshot_service.h b/libs/vr/libvrflinger/screenshot_service.h
index ec4c527..f59e872 100644
--- a/libs/vr/libvrflinger/screenshot_service.h
+++ b/libs/vr/libvrflinger/screenshot_service.h
@@ -38,7 +38,7 @@
  public:
   ~ScreenshotService();
 
-  int HandleMessage(pdx::Message& message) override;
+  pdx::Status<void> HandleMessage(pdx::Message& message) override;
 
   // Returns true if there is a pending screenshot request.
   bool IsScreenshotRequestPending() const {
diff --git a/libs/vr/libvrflinger/surface_channel.cpp b/libs/vr/libvrflinger/surface_channel.cpp
index 8aa220b..263b382 100644
--- a/libs/vr/libvrflinger/surface_channel.cpp
+++ b/libs/vr/libvrflinger/surface_channel.cpp
@@ -7,7 +7,7 @@
 namespace android {
 namespace dvr {
 
-int SurfaceChannel::HandleMessage(Message& message) {
+pdx::Status<void> SurfaceChannel::HandleMessage(Message& message) {
   switch (message.GetOp()) {
     case DisplayRPC::GetMetadataBuffer::Opcode:
       DispatchRemoteMethod<DisplayRPC::GetMetadataBuffer>(
@@ -15,7 +15,7 @@
       break;
   }
 
-  return 0;
+  return {};
 }
 
 BorrowedChannelHandle SurfaceChannel::OnGetMetadataBuffer(Message& message) {
diff --git a/libs/vr/libvrflinger/surface_channel.h b/libs/vr/libvrflinger/surface_channel.h
index 870e1a4..bb6b1c5 100644
--- a/libs/vr/libvrflinger/surface_channel.h
+++ b/libs/vr/libvrflinger/surface_channel.h
@@ -33,7 +33,7 @@
 
   // Dispatches surface channel messages to the appropriate handlers. This
   // handler runs on the displayd message dispatch thread.
-  virtual int HandleMessage(pdx::Message& message);
+  virtual pdx::Status<void> HandleMessage(pdx::Message& message);
 
  protected:
   // Contains the surface metadata.
diff --git a/libs/vr/libvrflinger/video_mesh_surface.cpp b/libs/vr/libvrflinger/video_mesh_surface.cpp
index a961a3d..d915a4a 100644
--- a/libs/vr/libvrflinger/video_mesh_surface.cpp
+++ b/libs/vr/libvrflinger/video_mesh_surface.cpp
@@ -14,7 +14,7 @@
 
 VideoMeshSurface::~VideoMeshSurface() {}
 
-int VideoMeshSurface::HandleMessage(Message& message) {
+pdx::Status<void> VideoMeshSurface::HandleMessage(Message& message) {
   ATRACE_NAME("VideoMeshSurface::HandleMessage");
 
   switch (message.GetOp()) {
@@ -27,7 +27,7 @@
       return SurfaceChannel::HandleMessage(message);
   }
 
-  return 0;
+  return {};
 }
 
 std::shared_ptr<ConsumerQueue> VideoMeshSurface::GetConsumerQueue() {
diff --git a/libs/vr/libvrflinger/video_mesh_surface.h b/libs/vr/libvrflinger/video_mesh_surface.h
index 1370793..2c9f3e8 100644
--- a/libs/vr/libvrflinger/video_mesh_surface.h
+++ b/libs/vr/libvrflinger/video_mesh_surface.h
@@ -12,7 +12,7 @@
 
 // VideoMeshSurface takes three inputs: 1) buffers filled by Android system
 // components (e.g. MediaCodec or camera stack) other than applications' GL
-// context; 2) a 3D mesh choosen by application to define the shape of the
+// context; 2) a 3D mesh chosen by application to define the shape of the
 // surface; 3) a transformation matrix from application to define the rotation,
 // position, and scaling of the video surface.
 class VideoMeshSurface : public SurfaceChannel {
@@ -33,7 +33,7 @@
     }
   }
 
-  int HandleMessage(Message& message) override;
+  pdx::Status<void> HandleMessage(Message& message) override;
 
   std::shared_ptr<ConsumerQueue> GetConsumerQueue();
 
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
index 48fa2c2..612b9b2 100644
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ b/libs/vr/libvrflinger/vsync_service.cpp
@@ -107,26 +107,26 @@
   }
 }
 
-int VSyncService::HandleMessage(pdx::Message& message) {
+pdx::Status<void> VSyncService::HandleMessage(pdx::Message& message) {
   switch (message.GetOp()) {
     case DisplayVSyncRPC::Wait::Opcode:
       AddWaiter(message);
-      return 0;
+      return {};
 
     case DisplayVSyncRPC::GetLastTimestamp::Opcode:
       DispatchRemoteMethod<DisplayVSyncRPC::GetLastTimestamp>(
           *this, &VSyncService::OnGetLastTimestamp, message);
-      return 0;
+      return {};
 
     case DisplayVSyncRPC::GetSchedInfo::Opcode:
       DispatchRemoteMethod<DisplayVSyncRPC::GetSchedInfo>(
           *this, &VSyncService::OnGetSchedInfo, message);
-      return 0;
+      return {};
 
     case DisplayVSyncRPC::Acknowledge::Opcode:
       DispatchRemoteMethod<DisplayVSyncRPC::Acknowledge>(
           *this, &VSyncService::OnAcknowledge, message);
-      return 0;
+      return {};
 
     default:
       return Service::HandleMessage(message);
diff --git a/libs/vr/libvrflinger/vsync_service.h b/libs/vr/libvrflinger/vsync_service.h
index ba1d4df..1c86d42 100644
--- a/libs/vr/libvrflinger/vsync_service.h
+++ b/libs/vr/libvrflinger/vsync_service.h
@@ -56,7 +56,7 @@
  public:
   ~VSyncService() override;
 
-  int HandleMessage(pdx::Message& message) override;
+  pdx::Status<void> HandleMessage(pdx::Message& message) override;
 
   std::shared_ptr<pdx::Channel> OnChannelOpen(pdx::Message& message) override;
   void OnChannelClose(pdx::Message& message,
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index 6d48f18..d59182e 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -15,6 +15,7 @@
 sourceFiles = [
     "pose_client.cpp",
     "sensor_client.cpp",
+    "latency_model.cpp",
 ]
 
 includeFiles = [
diff --git a/libs/vr/libvrsensor/include/private/dvr/latency_model.h b/libs/vr/libvrsensor/include/private/dvr/latency_model.h
new file mode 100644
index 0000000..40b4638
--- /dev/null
+++ b/libs/vr/libvrsensor/include/private/dvr/latency_model.h
@@ -0,0 +1,29 @@
+#ifndef ANDROID_DVR_LATENCY_MODEL_H_
+#define ANDROID_DVR_LATENCY_MODEL_H_
+
+#include <vector>
+
+namespace android {
+namespace dvr {
+
+// This class models the latency from sensors. It will look at the first
+// window_size measurements and return their average after that.
+class LatencyModel {
+ public:
+  LatencyModel(size_t window_size);
+  ~LatencyModel() = default;
+
+  void AddLatency(int64_t latency_ns);
+  int64_t CurrentLatencyEstimate() const { return latency_; }
+
+ private:
+  size_t window_size_;
+  int64_t latency_sum_ = 0;
+  size_t num_summed_ = 0;
+  int64_t latency_ = 0;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_LATENCY_MODEL_H_
diff --git a/libs/vr/libvrsensor/latency_model.cpp b/libs/vr/libvrsensor/latency_model.cpp
new file mode 100644
index 0000000..d3a4521
--- /dev/null
+++ b/libs/vr/libvrsensor/latency_model.cpp
@@ -0,0 +1,24 @@
+#include <private/dvr/latency_model.h>
+
+#include <cmath>
+
+namespace android {
+namespace dvr {
+
+LatencyModel::LatencyModel(size_t window_size) : window_size_(window_size) {}
+
+void LatencyModel::AddLatency(int64_t latency_ns) {
+  // Not enough samples yet?
+  if (num_summed_ < window_size_) {
+    // Accumulate.
+    latency_sum_ += latency_ns;
+
+    // Have enough samples for latency estimate?
+    if (++num_summed_ == window_size_) {
+      latency_ = latency_sum_ / window_size_;
+    }
+  }
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 683e6ca..7d20ba1 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -33,6 +33,10 @@
 #include "egl_trace.h"
 #include "egldefs.h"
 
+extern "C" {
+  android_namespace_t* android_get_exported_namespace(const char*);
+}
+
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
@@ -106,6 +110,11 @@
     return dlopen(path, mode);
 }
 
+static void* do_android_dlopen_ext(const char* path, int mode, const android_dlextinfo* info) {
+    ATRACE_CALL();
+    return android_dlopen_ext(path, mode, info);
+}
+
 // ----------------------------------------------------------------------------
 
 Loader::driver_t::driver_t(void* gles)
@@ -414,6 +423,27 @@
     }
     const char* const driver_absolute_path = absolutePath.c_str();
 
+    // Try to load drivers from the 'sphal' namespace, if it exist. Fall back to
+    // the original routine when the namespace does not exist or the load from
+    // the namespace fails.
+    // See /system/core/rootdir/etc/ld.config.txt for the configuration of the
+    // sphal namespace.
+    android_namespace_t* sphal_namespace = android_get_exported_namespace("sphal");
+    if (sphal_namespace != NULL) {
+        const android_dlextinfo dlextinfo = {
+            .flags = ANDROID_DLEXT_USE_NAMESPACE,
+            .library_namespace = sphal_namespace,
+        };
+        void* dso = do_android_dlopen_ext(driver_absolute_path, RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+        if (dso) {
+            ALOGD("loaded %s from sphal namespace", driver_absolute_path);
+            return dso;
+        }
+        else {
+            ALOGW("failed to load %s from sphal namespace: %s", driver_absolute_path, dlerror());
+        }
+    }
+
     void* dso = do_dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
     if (dso == 0) {
         const char* err = dlerror();
@@ -426,11 +456,6 @@
     return dso;
 }
 
-static void* do_android_dlopen_ext(const char* path, int mode, const android_dlextinfo* info) {
-    ATRACE_CALL();
-    return android_dlopen_ext(path, mode, info);
-}
-
 static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = {
     "ro.hardware.egl",
     "ro.board.platform",
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 7ed34be..6238780 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -114,7 +114,7 @@
         // call the implementation's glGetString(GL_EXTENSIONS)
         const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS);
         gl_extensions = exts;
-        if (gl_extensions.find("GL_EXT_debug_marker") != std::string::npos) {
+        if (gl_extensions.find("GL_EXT_debug_marker") == std::string::npos) {
             gl_extensions.insert(0, "GL_EXT_debug_marker ");
         }
 
diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk
index b772450..5620496 100644
--- a/opengl/tests/EGLTest/Android.mk
+++ b/opengl/tests/EGLTest/Android.mk
@@ -12,12 +12,17 @@
     EGL_test.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
+	android.hardware.configstore@1.0 \
+	android.hardware.configstore-utils \
 	libEGL \
 	libcutils \
 	libbinder \
+	libhidlbase \
+	libhidltransport \
 	libutils \
 	libgui \
 	libbase \
+	liblog \
 
 LOCAL_C_INCLUDES := \
     bionic/libc/private \
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 1b3086b..94de5af 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -16,6 +16,9 @@
 
 #include <gtest/gtest.h>
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+
+#include <configstore/Utils.h>
 #include <utils/String8.h>
 
 #include <EGL/egl.h>
@@ -25,10 +28,31 @@
 #include <gui/IGraphicBufferConsumer.h>
 #include <gui/BufferQueue.h>
 
+#define PIXEL_FORMAT_FLOAT "EGL_EXT_pixel_format_float"
+
+bool hasEglPixelFormatFloat() {
+    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
+    size_t cropExtLen = strlen(PIXEL_FORMAT_FLOAT);
+    size_t extsLen = strlen(exts);
+    bool equal = !strcmp(PIXEL_FORMAT_FLOAT, exts);
+    bool atStart = !strncmp(PIXEL_FORMAT_FLOAT " ", exts, cropExtLen + 1);
+    bool atEnd = (cropExtLen + 1) < extsLen &&
+            !strcmp(" " PIXEL_FORMAT_FLOAT, exts + extsLen - (cropExtLen + 1));
+    bool inMiddle = strstr(exts, " " PIXEL_FORMAT_FLOAT " ");
+    return equal || atStart || atEnd || inMiddle;
+}
+
 namespace android {
 
 #define EGL_UNSIGNED_TRUE static_cast<EGLBoolean>(EGL_TRUE)
 
+// retrieve wide-color setting from configstore
+using namespace android::hardware::configstore;
+
+static bool hasWideColorDisplay =
+        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+
 class EGLTest : public ::testing::Test {
 protected:
     EGLDisplay mEglDisplay;
@@ -169,5 +193,75 @@
     EXPECT_GE(components[3], 8);
 }
 
+TEST_F(EGLTest, EGLConfigFP16) {
+    EGLint numConfigs;
+    EGLConfig config;
+    EGLBoolean success;
 
+    if (!hasWideColorDisplay) {
+        // skip this test if device does not have wide-color display
+        return;
+    }
+
+    ASSERT_TRUE(hasEglPixelFormatFloat());
+
+    EGLint attrs[] = {EGL_SURFACE_TYPE,
+                      EGL_WINDOW_BIT,
+                      EGL_RENDERABLE_TYPE,
+                      EGL_OPENGL_ES2_BIT,
+                      EGL_RED_SIZE,
+                      16,
+                      EGL_GREEN_SIZE,
+                      16,
+                      EGL_BLUE_SIZE,
+                      16,
+                      EGL_ALPHA_SIZE,
+                      16,
+                      EGL_COLOR_COMPONENT_TYPE_EXT,
+                      EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
+                      EGL_NONE};
+    success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(1, numConfigs);
+
+    EGLint components[4];
+
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    EXPECT_GE(components[0], 16);
+    EXPECT_GE(components[1], 16);
+    EXPECT_GE(components[2], 16);
+    EXPECT_GE(components[3], 16);
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
+    // Create a EGLSurface
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    consumer->consumerConnect(new DummyConsumer, false);
+    sp<Surface> mSTC = new Surface(producer);
+    sp<ANativeWindow> mANW = mSTC;
+
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
 }
diff --git a/services/schedulerservice/Android.bp b/services/schedulerservice/Android.bp
new file mode 100644
index 0000000..1f1340c
--- /dev/null
+++ b/services/schedulerservice/Android.bp
@@ -0,0 +1,25 @@
+cc_library_shared {
+    name: "libschedulerservicehidl",
+    srcs: [
+        "SchedulingPolicyService.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libmediautils",
+        "liblog",
+        "libutils",
+        "android.hidl.base@1.0",
+        "android.frameworks.schedulerservice@1.0",
+    ],
+    header_libs: [
+        "libcutils_headers",
+    ],
+    export_include_dirs: [
+        "include/"
+    ],
+    local_include_dirs: [
+        "include/schedulerservice/",
+    ],
+}
diff --git a/services/schedulerservice/SchedulingPolicyService.cpp b/services/schedulerservice/SchedulingPolicyService.cpp
new file mode 100644
index 0000000..522a8c0
--- /dev/null
+++ b/services/schedulerservice/SchedulingPolicyService.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "schedulerservicehidl"
+
+#include "SchedulingPolicyService.h"
+
+#include <private/android_filesystem_config.h> // for AID_CAMERASERVER
+
+#include <log/log.h>
+#include <hwbinder/IPCThreadState.h>
+#include <mediautils/SchedulingPolicyService.h>
+
+namespace android {
+namespace frameworks {
+namespace schedulerservice {
+namespace V1_0 {
+namespace implementation {
+
+Return<bool> SchedulingPolicyService::requestPriority(int32_t pid, int32_t tid, int32_t priority) {
+    using ::android::hardware::IPCThreadState;
+
+    if (priority < static_cast<int32_t>(Priority::MIN) ||
+            priority > static_cast<int32_t>(Priority::MAX)) {
+        return false;
+    }
+
+    if (IPCThreadState::self()->getCallingUid() != AID_CAMERASERVER) {
+        return false;
+    }
+
+    // this should always be allowed since we are in system_server.
+    int value = ::android::requestPriority(pid, tid, priority, false /* isForApp */);
+    return value == 0 /* success */;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace schedulerservice
+}  // namespace frameworks
+}  // namespace android
diff --git a/services/schedulerservice/include/schedulerservice/SchedulingPolicyService.h b/services/schedulerservice/include/schedulerservice/SchedulingPolicyService.h
new file mode 100644
index 0000000..eb5a4ae
--- /dev/null
+++ b/services/schedulerservice/include/schedulerservice/SchedulingPolicyService.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <android/frameworks/schedulerservice/1.0/ISchedulingPolicyService.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace frameworks {
+namespace schedulerservice {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::frameworks::schedulerservice::V1_0::ISchedulingPolicyService;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct SchedulingPolicyService : public ISchedulingPolicyService {
+    Return<bool> requestPriority(int32_t pid, int32_t tid, int32_t priority) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace schedulerservice
+}  // namespace frameworks
+}  // namespace android
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8fc4921..4d76272 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,23 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#include <cutils/properties.h>
-
 #include <binder/AppOpsManager.h>
 #include <binder/BinderService.h>
 #include <binder/IServiceManager.h>
 #include <binder/PermissionCache.h>
-
 #include <cutils/ashmem.h>
-#include <sensor/SensorEventQueue.h>
-
+#include <cutils/properties.h>
 #include <hardware/sensors.h>
 #include <hardware_legacy/power.h>
-
 #include <openssl/digest.h>
 #include <openssl/hmac.h>
 #include <openssl/rand.h>
+#include <sensor/SensorEventQueue.h>
+#include <utils/SystemClock.h>
 
 #include "BatteryService.h"
 #include "CorrectedGyroSensor.h"
@@ -77,7 +73,8 @@
 #define SENSOR_SERVICE_SCHED_FIFO_PRIORITY 10
 
 // Permissions.
-static const String16 sDump("android.permission.DUMP");
+static const String16 sDumpPermission("android.permission.DUMP");
+static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE");
 
 SensorService::SensorService()
     : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
@@ -319,7 +316,7 @@
 
 status_t SensorService::dump(int fd, const Vector<String16>& args) {
     String8 result;
-    if (!PermissionCache::checkCallingPermission(sDump)) {
+    if (!PermissionCache::checkCallingPermission(sDumpPermission)) {
         result.appendFormat("Permission Denial: can't dump SensorService from pid=%d, uid=%d\n",
                 IPCThreadState::self()->getCallingPid(),
                 IPCThreadState::self()->getCallingUid());
@@ -1032,6 +1029,84 @@
     return conn;
 }
 
+int SensorService::setOperationParameter(
+            int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) {
+    Mutex::Autolock _l(mLock);
+
+    // check permission
+    int32_t uid;
+    bool hasPermission = checkCallingPermission(sLocationHardwarePermission, nullptr, &uid);
+    if (!hasPermission || (uid != 1000 && uid != 0)) {
+        return PERMISSION_DENIED;
+    }
+
+    bool isFloat = true;
+    size_t expectSize = INT32_MAX;
+    switch (type) {
+        case AINFO_LOCAL_GEOMAGNETIC_FIELD:
+            isFloat = true;
+            expectSize = 3;
+            break;
+        case AINFO_LOCAL_GRAVITY:
+            isFloat = true;
+            expectSize = 1;
+            break;
+        case AINFO_DOCK_STATE:
+        case AINFO_HIGH_PERFORMANCE_MODE:
+        case AINFO_MAGNETIC_FIELD_CALIBRATION:
+            isFloat = false;
+            expectSize = 1;
+            break;
+        default:
+            return BAD_VALUE;
+    }
+
+    // three events: first one is begin tag, last one is end tag, the one in the middle
+    // is the payload.
+    sensors_event_t event[3];
+    int64_t timestamp = elapsedRealtimeNano();
+    for (sensors_event_t* i = event; i < event + 3; i++) {
+        *i = (sensors_event_t) {
+            .version = sizeof(sensors_event_t),
+            .sensor = 0,
+            .type = SENSOR_TYPE_ADDITIONAL_INFO,
+            .timestamp = timestamp++,
+            .additional_info = (additional_info_event_t) {
+                .serial = 0
+            }
+        };
+    }
+
+    event[0].additional_info.type = AINFO_BEGIN;
+    event[1].additional_info.type = type;
+    event[2].additional_info.type = AINFO_END;
+
+    if (isFloat) {
+        if (floats.size() != expectSize) {
+            return BAD_VALUE;
+        }
+        for (size_t i = 0; i < expectSize; ++i) {
+            event[1].additional_info.data_float[i] = floats[i];
+        }
+    } else {
+        if (ints.size() != expectSize) {
+            return BAD_VALUE;
+        }
+        for (size_t i = 0; i < expectSize; ++i) {
+            event[1].additional_info.data_int32[i] = ints[i];
+        }
+    }
+
+    SensorDevice& dev(SensorDevice::getInstance());
+    for (sensors_event_t* i = event; i < event + 3; i++) {
+        int ret = dev.injectSensorData(i);
+        if (ret != NO_ERROR) {
+            return ret;
+        }
+    }
+    return NO_ERROR;
+}
+
 status_t SensorService::resetToNormalMode() {
     Mutex::Autolock _l(mLock);
     return resetToNormalModeLocked();
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index d0be121..2a9d6e8 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -158,6 +158,8 @@
     virtual int isDataInjectionEnabled();
     virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
             uint32_t size, int32_t type, int32_t format, const native_handle *resource);
+    virtual int setOperationParameter(
+            int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
     virtual status_t dump(int fd, const Vector<String16>& args);
 
     String8 getSensorName(int handle) const;
diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp
index f00c297..748dafc 100644
--- a/services/sensorservice/hidl/Android.bp
+++ b/services/sensorservice/hidl/Android.bp
@@ -1,6 +1,7 @@
 cc_library_shared {
     name: "libsensorservicehidl",
     srcs: [
+        "EventQueue.cpp",
         "DirectReportChannel.cpp",
         "SensorManager.cpp",
         "utils.cpp",
@@ -19,6 +20,9 @@
         "android.hardware.sensors@1.0",
         "android.hidl.base@1.0",
     ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+    ],
     export_include_dirs: [
         "include/"
     ],
diff --git a/services/sensorservice/hidl/DirectReportChannel.cpp b/services/sensorservice/hidl/DirectReportChannel.cpp
index 9caba47..773ce8c 100644
--- a/services/sensorservice/hidl/DirectReportChannel.cpp
+++ b/services/sensorservice/hidl/DirectReportChannel.cpp
@@ -32,8 +32,9 @@
 
 // Methods from ::android::frameworks::sensorservice::V1_0::IDirectReportChannel follow.
 Return<Result> DirectReportChannel::configure(int32_t sensorHandle, RateLevel rate) {
-    return convertResult(mManager.configureDirectChannel(mId,
-            static_cast<int>(sensorHandle), static_cast<int>(rate)));
+    int token = mManager.configureDirectChannel(mId,
+            static_cast<int>(sensorHandle), static_cast<int>(rate));
+    return token <= 0 ? convertResult(token) : Result::OK;
 }
 
 
diff --git a/services/sensorservice/hidl/DirectReportChannel.h b/services/sensorservice/hidl/DirectReportChannel.h
index f4cd4e7..9134944 100644
--- a/services/sensorservice/hidl/DirectReportChannel.h
+++ b/services/sensorservice/hidl/DirectReportChannel.h
@@ -41,7 +41,7 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
-struct DirectReportChannel : public IDirectReportChannel {
+struct DirectReportChannel final : public IDirectReportChannel {
 
     DirectReportChannel(::android::SensorManager& manager, int channelId);
     ~DirectReportChannel();
diff --git a/services/sensorservice/hidl/EventQueue.cpp b/services/sensorservice/hidl/EventQueue.cpp
new file mode 100644
index 0000000..86d365c
--- /dev/null
+++ b/services/sensorservice/hidl/EventQueue.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventQueue.h"
+#include "utils.h"
+
+#include <utils/Looper.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace V1_0 {
+namespace implementation {
+
+class EventQueueLooperCallback : public ::android::LooperCallback {
+public:
+    EventQueueLooperCallback(sp<EventQueue> queue, sp<IEventQueueCallback> callback)
+            : mQueue(queue), mCallback(callback) {
+    }
+
+    int handleEvent(__unused int fd, __unused int events, __unused void* data) {
+
+        ASensorEvent event;
+        ssize_t actual;
+        const sp<::android::SensorEventQueue>& internalQueue = mQueue->mInternalQueue;
+
+        while ((actual = internalQueue->read(&event, 1 /* count */)) > 0) {
+            internalQueue->sendAck(&event, actual);
+            mCallback->onEvent(convertEvent(event));
+        }
+
+        return 1; // continue to receive callbacks
+    }
+
+private:
+    sp<EventQueue> mQueue;
+    sp<IEventQueueCallback> mCallback;
+};
+
+EventQueue::EventQueue(
+        sp<IEventQueueCallback> callback,
+        sp<::android::Looper> looper,
+        sp<::android::SensorEventQueue> internalQueue)
+            : mLooper(looper),
+              mInternalQueue(internalQueue) {
+
+    mLooper->addFd(mInternalQueue->getFd(), ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT,
+            new EventQueueLooperCallback(this, callback), NULL /* data */);
+}
+
+EventQueue::~EventQueue() {
+    mLooper->removeFd(mInternalQueue->getFd());
+}
+
+// Methods from ::android::frameworks::sensorservice::V1_0::IEventQueue follow.
+Return<Result> EventQueue::enableSensor(int32_t sensorHandle, int32_t samplingPeriodUs,
+        int64_t maxBatchReportLatencyUs) {
+    // TODO implement
+    return convertResult(mInternalQueue->enableSensor(sensorHandle, samplingPeriodUs,
+            maxBatchReportLatencyUs, 0 /* reserved flags */));
+}
+
+Return<Result> EventQueue::disableSensor(int32_t sensorHandle) {
+    return convertResult(mInternalQueue->disableSensor(sensorHandle));
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sensorservice
+}  // namespace frameworks
+}  // namespace android
diff --git a/services/sensorservice/hidl/EventQueue.h b/services/sensorservice/hidl/EventQueue.h
new file mode 100644
index 0000000..87c614b
--- /dev/null
+++ b/services/sensorservice/hidl/EventQueue.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_EVENTQUEUE_H
+#define ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_EVENTQUEUE_H
+
+#include "SensorManager.h"
+
+#include <android/frameworks/sensorservice/1.0/IEventQueue.h>
+#include <android/frameworks/sensorservice/1.0/IEventQueueCallback.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <sensor/SensorManager.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::frameworks::sensorservice::V1_0::IEventQueue;
+using ::android::frameworks::sensorservice::V1_0::IEventQueueCallback;
+using ::android::frameworks::sensorservice::V1_0::Result;
+using ::android::hardware::Return;
+using ::android::sp;
+
+struct EventQueue final : public IEventQueue {
+    EventQueue(
+        sp<IEventQueueCallback> callback,
+        sp<::android::Looper> looper,
+        sp<::android::SensorEventQueue> internalQueue);
+    ~EventQueue();
+
+    // Methods from ::android::frameworks::sensorservice::V1_0::IEventQueue follow.
+    Return<Result> enableSensor(int32_t sensorHandle, int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs) override;
+    Return<Result> disableSensor(int32_t sensorHandle) override;
+
+private:
+    friend class EventQueueLooperCallback;
+    sp<::android::Looper> mLooper;
+    sp<::android::SensorEventQueue> mInternalQueue;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sensorservice
+}  // namespace frameworks
+}  // namespace android
+
+#endif  // ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_EVENTQUEUE_H
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index 37e53dc..0743fc3 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -20,10 +20,14 @@
 #endif
 #include <android-base/logging.h>
 
-#include "DirectReportChannel.h"
 #include "SensorManager.h"
+
+#include "EventQueue.h"
+#include "DirectReportChannel.h"
 #include "utils.h"
 
+#include <thread>
+
 namespace android {
 namespace frameworks {
 namespace sensorservice {
@@ -31,19 +35,28 @@
 namespace implementation {
 
 using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Void;
 using ::android::sp;
 
 SensorManager::SensorManager()
-        : mManager{::android::SensorManager::getInstanceForPackage(
+        : mInternalManager{::android::SensorManager::getInstanceForPackage(
             String16(ISensorManager::descriptor))} {
 }
 
+SensorManager::~SensorManager() {
+    // Stops pollAll inside the thread.
+    std::unique_lock<std::mutex> lock(mLooperMutex);
+    if (mLooper != nullptr) {
+        mLooper->wake();
+    }
+}
+
 // Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
 Return<void> SensorManager::getSensorList(getSensorList_cb _hidl_cb) {
     ::android::Sensor const* const* list;
-    ssize_t count = mManager.getSensorList(&list);
+    ssize_t count = mInternalManager.getSensorList(&list);
     if (count < 0 || !list) {
         LOG(ERROR) << "::android::SensorManager::getSensorList encounters " << count;
         _hidl_cb({}, Result::UNKNOWN_ERROR);
@@ -59,7 +72,7 @@
 }
 
 Return<void> SensorManager::getDefaultSensor(SensorType type, getDefaultSensor_cb _hidl_cb) {
-    ::android::Sensor const* sensor = mManager.getDefaultSensor(static_cast<int>(type));
+    ::android::Sensor const* sensor = mInternalManager.getDefaultSensor(static_cast<int>(type));
     if (!sensor) {
         _hidl_cb({}, Result::NOT_EXIST);
         return Void();
@@ -90,12 +103,12 @@
 Return<void> SensorManager::createAshmemDirectChannel(
         const hidl_memory& mem, uint64_t size,
         createAshmemDirectChannel_cb _hidl_cb) {
-    if (size > mem.size()) {
+    if (size > mem.size() || size < (uint64_t)SensorsEventFormatOffset::TOTAL_LENGTH) {
         _hidl_cb(nullptr, Result::BAD_VALUE);
         return Void();
     }
 
-    createDirectChannel(mManager, size, SENSOR_DIRECT_MEM_TYPE_ASHMEM,
+    createDirectChannel(mInternalManager, size, SENSOR_DIRECT_MEM_TYPE_ASHMEM,
             mem.handle(), _hidl_cb);
 
     return Void();
@@ -105,16 +118,53 @@
         const hidl_handle& buffer, uint64_t size,
         createGrallocDirectChannel_cb _hidl_cb) {
 
-    createDirectChannel(mManager, size, SENSOR_DIRECT_MEM_TYPE_GRALLOC,
+    createDirectChannel(mInternalManager, size, SENSOR_DIRECT_MEM_TYPE_GRALLOC,
             buffer.getNativeHandle(), _hidl_cb);
 
     return Void();
 }
 
+/* One global looper for all event queues created from this SensorManager. */
+sp<::android::Looper> SensorManager::getLooper() {
+    std::unique_lock<std::mutex> lock(mLooperMutex);
+    if (mLooper == nullptr) {
+        std::condition_variable looperSet;
+
+        std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet] {
+            std::unique_lock<std::mutex> lock(mutex);
+            looper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS /* opts */);
+            lock.unlock();
+
+            looperSet.notify_one();
+            int pollResult = looper->pollAll(-1 /* timeout */);
+            if (pollResult != ALOOPER_POLL_WAKE) {
+                LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult;
+            }
+            LOG(INFO) << "Looper thread is terminated.";
+        }}.detach();
+        looperSet.wait(lock, [this]{ return this->mLooper != nullptr; });
+    }
+    return mLooper;
+}
+
 Return<void> SensorManager::createEventQueue(
-        __unused const sp<IEventQueueCallback> &callback, createEventQueue_cb _hidl_cb) {
-    // TODO(b/35219747) Implement this
-    _hidl_cb(nullptr, Result::UNKNOWN_ERROR);
+        const sp<IEventQueueCallback> &callback, createEventQueue_cb _hidl_cb) {
+    if (callback == nullptr) {
+        _hidl_cb(nullptr, Result::BAD_VALUE);
+        return Void();
+    }
+
+    sp<::android::Looper> looper = getLooper();
+    sp<::android::SensorEventQueue> internalQueue = mInternalManager.createEventQueue();
+    if (internalQueue == nullptr) {
+        LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr.";
+        _hidl_cb(nullptr, Result::UNKNOWN_ERROR);
+        return Void();
+    }
+
+    sp<IEventQueue> queue = new EventQueue(callback, looper, internalQueue);
+    _hidl_cb(queue, Result::OK);
+
     return Void();
 }
 
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index 0b026c9..a2372df 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -17,11 +17,14 @@
 #ifndef ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_SENSORMANAGER_H
 #define ANDROID_FRAMEWORKS_SENSORSERVICE_V1_0_SENSORMANAGER_H
 
+#include <mutex>
+
 #include <android/frameworks/sensorservice/1.0/ISensorManager.h>
 #include <android/frameworks/sensorservice/1.0/types.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 #include <sensor/SensorManager.h>
+#include <utils/Looper.h>
 
 namespace android {
 namespace frameworks {
@@ -34,9 +37,10 @@
 using ::android::hardware::hidl_memory;
 using ::android::hardware::Return;
 
-struct SensorManager : public ISensorManager {
+struct SensorManager final : public ISensorManager {
 
     SensorManager();
+    ~SensorManager();
 
     // Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
     Return<void> getSensorList(getSensorList_cb _hidl_cb) override;
@@ -44,9 +48,13 @@
     Return<void> createAshmemDirectChannel(const hidl_memory& mem, uint64_t size, createAshmemDirectChannel_cb _hidl_cb) override;
     Return<void> createGrallocDirectChannel(const hidl_handle& buffer, uint64_t size, createGrallocDirectChannel_cb _hidl_cb) override;
     Return<void> createEventQueue(const sp<IEventQueueCallback> &callback, createEventQueue_cb _hidl_cb);
-private:
-    ::android::SensorManager& mManager;
 
+private:
+    sp<::android::Looper> getLooper();
+
+    ::android::SensorManager& mInternalManager;
+    std::mutex mLooperMutex;
+    sp<::android::Looper> mLooper;
 };
 
 }  // namespace implementation
diff --git a/services/sensorservice/hidl/utils.cpp b/services/sensorservice/hidl/utils.cpp
index 4e02741..b540525 100644
--- a/services/sensorservice/hidl/utils.cpp
+++ b/services/sensorservice/hidl/utils.cpp
@@ -16,6 +16,8 @@
 
 #include "utils.h"
 
+#include <sensors/convert.h>
+
 namespace android {
 namespace frameworks {
 namespace sensorservice {
@@ -26,7 +28,7 @@
 using ::android::hardware::hidl_string;
 using ::android::hardware::sensors::V1_0::SensorInfo;
 
-SensorInfo convertSensor(const Sensor &src) {
+SensorInfo convertSensor(const Sensor& src) {
     SensorInfo dst;
     const String8& name = src.getName();
     const String8& vendor = src.getVendor();
@@ -36,7 +38,7 @@
     dst.sensorHandle = src.getHandle();
     dst.type = static_cast<::android::hardware::sensors::V1_0::SensorType>(
             src.getType());
-    // FIXME maxRange uses maxValue because ::android::Sensor wraps the
+    // maxRange uses maxValue because ::android::Sensor wraps the
     // internal sensor_t in this way.
     dst.maxRange = src.getMaxValue();
     dst.resolution = src.getResolution();
@@ -70,6 +72,13 @@
     }
 }
 
+::android::hardware::sensors::V1_0::Event convertEvent(const ::ASensorEvent& src) {
+    ::android::hardware::sensors::V1_0::Event dst;
+    ::android::hardware::sensors::V1_0::implementation::convertFromSensorEvent(
+            reinterpret_cast<const sensors_event_t&>(src), &dst);
+    return dst;
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace sensorservice
diff --git a/services/sensorservice/hidl/utils.h b/services/sensorservice/hidl/utils.h
index 0606e69..b350928 100644
--- a/services/sensorservice/hidl/utils.h
+++ b/services/sensorservice/hidl/utils.h
@@ -30,6 +30,8 @@
 ::android::hardware::sensors::V1_0::SensorInfo convertSensor(const ::android::Sensor &src);
 Result convertResult(status_t status);
 
+::android::hardware::sensors::V1_0::Event convertEvent(const ::ASensorEvent &event);
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace sensorservice
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 647a4c0..76baa01 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -66,9 +66,6 @@
 
 LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
 
-LOCAL_HEADER_LIBRARIES := \
-    android.hardware.configstore-utils
-
 LOCAL_STATIC_LIBRARIES := \
     libhwcomposer-command-buffer \
     libtrace_proto \
@@ -77,10 +74,11 @@
     libvrflinger
 
 LOCAL_SHARED_LIBRARIES := \
-    android.dvr.composer@1.0 \
+    android.frameworks.vr.composer@1.0 \
     android.hardware.graphics.allocator@2.0 \
     android.hardware.graphics.composer@2.1 \
     android.hardware.configstore@1.0 \
+    android.hardware.configstore-utils \
     libcutils \
     liblog \
     libdl \
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index c3b48ca..b5ffc60 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -80,6 +80,7 @@
 
 uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0;
 
+// clang-format off
 DisplayDevice::DisplayDevice(
         const sp<SurfaceFlinger>& flinger,
         DisplayType type,
@@ -91,7 +92,8 @@
         const wp<IBinder>& displayToken,
         const sp<DisplaySurface>& displaySurface,
         const sp<IGraphicBufferProducer>& producer,
-        EGLConfig config)
+        EGLConfig config,
+        bool supportWideColor)
     : lastCompositionHadVisibleLayers(false),
       mFlinger(flinger),
       mType(type),
@@ -113,12 +115,16 @@
       mPowerMode(HWC_POWER_MODE_OFF),
       mActiveConfig(0)
 {
+    // clang-format on
     Surface* surface;
     mNativeWindow = surface = new Surface(producer, false);
     ANativeWindow* const window = mNativeWindow.get();
 
 #ifdef USE_HWC2
     mActiveColorMode = static_cast<android_color_mode_t>(-1);
+    mDisplayHasWideColor = supportWideColor;
+#else
+    (void) supportWideColor;
 #endif
     /*
      * Create our display's surface
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index caa7adc..e2852a7 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -83,6 +83,7 @@
         NO_LAYER_STACK = 0xFFFFFFFF,
     };
 
+    // clang-format off
     DisplayDevice(
             const sp<SurfaceFlinger>& flinger,
             DisplayType type,
@@ -94,7 +95,9 @@
             const wp<IBinder>& displayToken,
             const sp<DisplaySurface>& displaySurface,
             const sp<IGraphicBufferProducer>& producer,
-            EGLConfig config);
+            EGLConfig config,
+            bool supportWideColor);
+    // clang-format on
 
     ~DisplayDevice();
 
@@ -146,6 +149,7 @@
     status_t beginFrame(bool mustRecompose) const;
 #ifdef USE_HWC2
     status_t prepareFrame(HWComposer& hwc);
+    bool getWideColorSupport() const { return mDisplayHasWideColor; }
 #else
     status_t prepareFrame(const HWComposer& hwc) const;
 #endif
@@ -264,6 +268,11 @@
 #ifdef USE_HWC2
     // current active color mode
     android_color_mode_t mActiveColorMode;
+
+    // Need to know if display is wide-color capable or not.
+    // Initialized by SurfaceFlinger when the DisplayDevice is created.
+    // Fed to RenderEngine during composition.
+    bool mDisplayHasWideColor;
 #endif
 };
 
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index d9bddb5..33aa759 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -17,7 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "HwcComposer"
 
-#include <android/dvr/composer/1.0/IVrComposerClient.h>
+#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
 #include <inttypes.h>
 #include <log/log.h>
 #include <gui/BufferQueue.h>
@@ -26,7 +26,7 @@
 
 namespace android {
 
-using dvr::composer::V1_0::IVrComposerClient;
+using frameworks::vr::composer::V1_0::IVrComposerClient;
 using hardware::Return;
 using hardware::hidl_vec;
 using hardware::hidl_handle;
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 486bce4..a9bb2ba 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -21,7 +21,6 @@
 
 #include <cutils/compiler.h>
 
-#include <private/gui/BitTube.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/DisplayEventReceiver.h>
 
@@ -389,7 +388,7 @@
 
 EventThread::Connection::Connection(
         const sp<EventThread>& eventThread)
-    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
+    : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize)
 {
 }
 
@@ -403,12 +402,14 @@
     mEventThread->registerDisplayEventConnection(this);
 }
 
-sp<BitTube> EventThread::Connection::getDataChannel() const {
-    return mChannel;
+status_t EventThread::Connection::stealReceiveChannel(gui::BitTube* outChannel) {
+    outChannel->setReceiveFd(mChannel.moveReceiveFd());
+    return NO_ERROR;
 }
 
-void EventThread::Connection::setVsyncRate(uint32_t count) {
+status_t EventThread::Connection::setVsyncRate(uint32_t count) {
     mEventThread->setVsyncRate(count, this);
+    return NO_ERROR;
 }
 
 void EventThread::Connection::requestNextVsync() {
@@ -417,7 +418,7 @@
 
 status_t EventThread::Connection::postEvent(
         const DisplayEventReceiver::Event& event) {
-    ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
+    ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
     return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }
 
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 3f1d0bb..6a59fbb 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <private/gui/BitTube.h>
 #include <gui/DisplayEventReceiver.h>
 #include <gui/IDisplayEventConnection.h>
 
@@ -68,11 +69,11 @@
     private:
         virtual ~Connection();
         virtual void onFirstRef();
-        virtual sp<BitTube> getDataChannel() const;
-        virtual void setVsyncRate(uint32_t count);
-        virtual void requestNextVsync();    // asynchronous
+        status_t stealReceiveChannel(gui::BitTube* outChannel) override;
+        status_t setVsyncRate(uint32_t count) override;
+        void requestNextVsync() override;    // asynchronous
         sp<EventThread> const mEventThread;
-        sp<BitTube> const mChannel;
+        gui::BitTube mChannel;
     };
 
 public:
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 16d8160..c211c7b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1011,6 +1011,9 @@
     return inverse(tr);
 }
 
+/*
+ * onDraw will draw the current layer onto the presentable buffer
+ */
 void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
         bool useIdentityTransform) const
 {
@@ -1172,6 +1175,9 @@
 
     RenderEngine& engine(mFlinger->getRenderEngine());
     engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), getAlpha());
+#ifdef USE_HWC2
+    engine.setSourceDataSpace(mCurrentState.dataSpace);
+#endif
     engine.drawMesh(mMesh);
     engine.disableBlending();
 }
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index debea58..bca3430 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -25,7 +25,6 @@
 #include <utils/Log.h>
 
 #include <gui/IDisplayEventConnection.h>
-#include <private/gui/BitTube.h>
 
 #include "MessageQueue.h"
 #include "EventThread.h"
@@ -94,8 +93,8 @@
 {
     mEventThread = eventThread;
     mEvents = eventThread->createEventConnection();
-    mEventTube = mEvents->getDataChannel();
-    mLooper->addFd(mEventTube->getFd(), 0, Looper::EVENT_INPUT,
+    mEvents->stealReceiveChannel(&mEventTube);
+    mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT,
             MessageQueue::cb_eventReceiver, this);
 }
 
@@ -150,7 +149,7 @@
 int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
     ssize_t n;
     DisplayEventReceiver::Event buffer[8];
-    while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
+    while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
         for (int i=0 ; i<n ; i++) {
             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
                 mHandler->dispatchInvalidate();
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index aed0aa9..85a33c8 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -25,6 +25,7 @@
 #include <utils/Timers.h>
 #include <utils/Looper.h>
 
+#include <private/gui/BitTube.h>
 #include <gui/DisplayEventReceiver.h>
 
 #include "Barrier.h"
@@ -81,7 +82,7 @@
     sp<Looper> mLooper;
     sp<EventThread> mEventThread;
     sp<IDisplayEventConnection> mEvents;
-    sp<BitTube> mEventTube;
+    gui::BitTube mEventTube;
     sp<Handler> mHandler;
 
 
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 406e611..04fe182 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -14,11 +14,16 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
+#include <ui/ColorSpace.h>
+#include <ui/DebugUtils.h>
 #include <ui/Rect.h>
 
 #include <utils/String8.h>
@@ -35,6 +40,73 @@
 #include "Mesh.h"
 #include "Texture.h"
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
+#include <fstream>
+
+// ---------------------------------------------------------------------------
+#ifdef USE_HWC2
+bool checkGlError(const char* op, int lineNumber) {
+    bool errorFound = false;
+    GLint error = glGetError();
+    while (error != GL_NO_ERROR) {
+        errorFound = true;
+        error = glGetError();
+        ALOGV("after %s() (line # %d) glError (0x%x)\n", op, lineNumber, error);
+    }
+    return errorFound;
+}
+
+static constexpr bool outputDebugPPMs = false;
+
+void writePPM(const char* basename, GLuint width, GLuint height) {
+    ALOGV("writePPM #%s: %d x %d", basename, width, height);
+
+    std::vector<GLubyte> pixels(width * height * 4);
+    std::vector<GLubyte> outBuffer(width * height * 3);
+
+    // TODO(courtneygo): We can now have float formats, need
+    // to remove this code or update to support.
+    // Make returned pixels fit in uint32_t, one byte per component
+    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+    if (checkGlError(__FUNCTION__, __LINE__)) {
+        return;
+    }
+
+    std::string filename(basename);
+    filename.append(".ppm");
+    std::ofstream file(filename.c_str(), std::ios::binary);
+    if (!file.is_open()) {
+        ALOGE("Unable to open file: %s", filename.c_str());
+        ALOGE("You may need to do: \"adb shell setenforce 0\" to enable "
+              "surfaceflinger to write debug images");
+        return;
+    }
+
+    file << "P6\n";
+    file << width << "\n";
+    file << height << "\n";
+    file << 255 << "\n";
+
+    auto ptr = reinterpret_cast<char*>(pixels.data());
+    auto outPtr = reinterpret_cast<char*>(outBuffer.data());
+    for (int y = height - 1; y >= 0; y--) {
+        char* data = ptr + y * width * sizeof(uint32_t);
+
+        for (GLuint x = 0; x < width; x++) {
+            // Only copy R, G and B components
+            outPtr[0] = data[0];
+            outPtr[1] = data[1];
+            outPtr[2] = data[2];
+            data += sizeof(uint32_t);
+            outPtr += 3;
+        }
+    }
+    file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size());
+}
+#endif
+
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
@@ -59,6 +131,28 @@
             GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
 
     //mColorBlindnessCorrection = M;
+
+#ifdef USE_HWC2
+    // retrieve wide-color and hdr settings from configstore
+    using namespace android::hardware::configstore;
+    using namespace android::hardware::configstore::V1_0;
+
+    mPlatformHasWideColor =
+            getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+    if (mPlatformHasWideColor) {
+        // Compute sRGB to DisplayP3 color transform
+        // NOTE: For now, we are limiting wide-color support to
+        // Display-P3 only.
+        mat3 srgbToP3 = ColorSpace::DisplayP3().getXYZtoRGB() * ColorSpace::sRGB().getRGBtoXYZ();
+
+        // color transform needs to be transposed and expanded to 4x4
+        // to be what the shader wants
+        // mat has an initializer that expands mat3 to mat4, but
+        // not an assignment operator
+        mat4 gamutTransform(transpose(srgbToP3));
+        mSrgbToDisplayP3 = gamutTransform;
+    }
+#endif
 }
 
 GLES20RenderEngine::~GLES20RenderEngine() {
@@ -170,6 +264,42 @@
     }
 }
 
+#ifdef USE_HWC2
+void GLES20RenderEngine::setColorMode(android_color_mode mode) {
+    ALOGV("setColorMode: %s (0x%x)", decodeColorMode(mode).c_str(), mode);
+
+    if (mColorMode == mode) return;
+
+    if (!mPlatformHasWideColor || !mDisplayHasWideColor || mode == HAL_COLOR_MODE_SRGB ||
+        mode == HAL_COLOR_MODE_NATIVE) {
+        // We are returning back to our default color_mode
+        mUseWideColor = false;
+        mWideColorFrameCount = 0;
+    } else {
+        mUseWideColor = true;
+    }
+
+    mColorMode = mode;
+}
+
+void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) {
+    if (source == HAL_DATASPACE_UNKNOWN) {
+        // Treat UNKNOWN as SRGB
+        source = HAL_DATASPACE_V0_SRGB;
+    }
+    mDataSpace = source;
+}
+
+void GLES20RenderEngine::setWideColor(bool hasWideColor) {
+    ALOGV("setWideColor: %s", hasWideColor ? "true" : "false");
+    mDisplayHasWideColor = hasWideColor;
+}
+
+bool GLES20RenderEngine::usesWideColor() {
+    return mUseWideColor;
+}
+#endif
+
 void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) {
     GLuint target = texture.getTextureTarget();
     glBindTexture(target, texture.getTextureName());
@@ -242,8 +372,6 @@
 
 void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
 
-    ProgramCache::getInstance().useProgram(mState);
-
     if (mesh.getTexCoordsSize()) {
         glEnableVertexAttribArray(Program::texCoords);
         glVertexAttribPointer(Program::texCoords,
@@ -259,7 +387,32 @@
             mesh.getByteStride(),
             mesh.getPositions());
 
+#ifdef USE_HWC2
+    if (usesWideColor()) {
+        Description wideColorState = mState;
+        if (mDataSpace != HAL_DATASPACE_DISPLAY_P3) {
+            wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
+            ALOGV("drawMesh: gamut transform applied");
+        }
+        ProgramCache::getInstance().useProgram(wideColorState);
+
+        glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
+
+        if (outputDebugPPMs) {
+            std::ostringstream out;
+            out << "/data/texture_out" << mWideColorFrameCount++;
+            writePPM(out.str().c_str(), mVpWidth, mVpHeight);
+        }
+    } else {
+        ProgramCache::getInstance().useProgram(mState);
+
+        glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
+    }
+#else
+    ProgramCache::getInstance().useProgram(mState);
+
     glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
+#endif
 
     if (mesh.getTexCoordsSize()) {
         glDisableVertexAttribArray(Program::texCoords);
@@ -268,6 +421,13 @@
 
 void GLES20RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
+#ifdef USE_HWC2
+    if (usesWideColor()) {
+        result.append("Wide-color: On\n");
+    } else {
+        result.append("Wide-color: Off\n");
+    }
+#endif
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 7c3f9b5..19cbb60 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -72,6 +72,27 @@
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
             float alpha) override;
     virtual void setupDimLayerBlending(float alpha) override;
+
+    // Color management related functions and state
+    void setColorMode(android_color_mode mode);
+    void setSourceDataSpace(android_dataspace source);
+    void setWideColor(bool hasWideColor);
+    bool usesWideColor();
+
+    // Current color mode of display using the render engine
+    android_color_mode mColorMode = HAL_COLOR_MODE_NATIVE;
+
+    // Current dataspace of layer being rendered
+    android_dataspace mDataSpace = HAL_DATASPACE_V0_SRGB;
+
+    // Indicate if wide-color mode is needed or not
+    bool mPlatformHasWideColor = false;
+    bool mDisplayHasWideColor = false;
+    bool mUseWideColor = false;
+    uint64_t mWideColorFrameCount = 0;
+
+    // Currently only supporting sRGB and DisplayP3 color spaces
+    mat4 mSrgbToDisplayP3;
 #else
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
             int alpha);
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index d19137b..8b031bc 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -98,6 +98,10 @@
 #ifdef USE_HWC2
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) = 0;
     virtual void setupDimLayerBlending(float alpha) = 0;
+    virtual void setColorMode(android_color_mode mode) = 0;
+    virtual void setSourceDataSpace(android_dataspace source) = 0;
+    virtual void setWideColor(bool hasWideColor) = 0;
+    virtual bool usesWideColor() = 0;
 #else
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0;
     virtual void setupDimLayerBlending(int alpha) = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 834c1c4..26baaae 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -37,6 +37,7 @@
 
 #include <dvr/vr_flinger.h>
 
+#include <ui/DebugUtils.h>
 #include <ui/DisplayInfo.h>
 #include <ui/DisplayStatInfo.h>
 
@@ -119,6 +120,7 @@
 bool SurfaceFlinger::hasSyncFramework;
 bool SurfaceFlinger::useVrFlinger;
 int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
+bool SurfaceFlinger::hasWideColorDisplay;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -189,6 +191,9 @@
     maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
 
+    hasWideColorDisplay =
+            getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
 
@@ -867,13 +872,10 @@
 
 void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
         android_color_mode_t mode) {
-    ALOGD("Set active color mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
-          this);
     int32_t type = hw->getDisplayType();
     android_color_mode_t currentMode = hw->getActiveColorMode();
 
     if (mode == currentMode) {
-        ALOGD("Screen type=%d is already in color mode=%d", hw->getDisplayType(), mode);
         return;
     }
 
@@ -882,6 +884,9 @@
         return;
     }
 
+    ALOGD("Set active color mode: %s (%d), type=%d", decodeColorMode(mode).c_str(), mode,
+          hw->getDisplayType());
+
     hw->setActiveColorMode(mode);
     getHwComposer().setActiveColorMode(type, mode);
 }
@@ -902,17 +907,17 @@
             mFlinger.getDisplayColorModes(mDisplay, &modes);
             bool exists = std::find(std::begin(modes), std::end(modes), mMode) != std::end(modes);
             if (mMode < 0 || !exists) {
-                ALOGE("Attempt to set invalid active color mode = %d for display %p", mMode,
-                        mDisplay.get());
+                ALOGE("Attempt to set invalid active color mode %s (%d) for display %p",
+                      decodeColorMode(mMode).c_str(), mMode, mDisplay.get());
                 return true;
             }
             sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
             if (hw == nullptr) {
-                ALOGE("Attempt to set active color mode = %d for null display %p",
-                        mMode, mDisplay.get());
+                ALOGE("Attempt to set active color mode %s (%d) for null display %p",
+                      decodeColorMode(mMode).c_str(), mMode, mDisplay.get());
             } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
-                ALOGW("Attempt to set active color mode= %d for virtual display",
-                        mMode);
+                ALOGW("Attempt to set active color mode %s %d for virtual display",
+                      decodeColorMode(mMode).c_str(), mMode);
             } else {
                 mFlinger.setActiveColorModeInternal(hw, mMode);
             }
@@ -1144,10 +1149,30 @@
 
         sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc,
                 DisplayDevice::DISPLAY_PRIMARY, consumer);
-        sp<DisplayDevice> hw = new DisplayDevice(this,
-                DisplayDevice::DISPLAY_PRIMARY, disp, isSecure, token, fbs,
-                producer, mRenderEngine->getEGLConfig());
+
+        bool hasWideColorModes = false;
+        std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type);
+        for (android_color_mode_t colorMode : modes) {
+            switch (colorMode) {
+                case HAL_COLOR_MODE_DISPLAY_P3:
+                case HAL_COLOR_MODE_ADOBE_RGB:
+                case HAL_COLOR_MODE_DCI_P3:
+                    hasWideColorModes = true;
+                    break;
+                default:
+                    break;
+            }
+        }
+        sp<DisplayDevice> hw =
+                new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, disp, isSecure, token, fbs,
+                                  producer, mRenderEngine->getEGLConfig(),
+                                  hasWideColorModes && hasWideColorDisplay);
         mDisplays.add(token, hw);
+        android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
+        if (hasWideColorModes && hasWideColorDisplay) {
+            defaultColorMode = HAL_COLOR_MODE_SRGB;
+        }
+        setActiveColorModeInternal(hw, defaultColorMode);
     } else {
         auto type = DisplayDevice::DISPLAY_EXTERNAL;
         Mutex::Autolock _l(mStateLock);
@@ -1591,6 +1616,39 @@
     }
 }
 
+// pickColorMode translates a given dataspace into the best available color mode.
+// Currently only support sRGB and Display-P3.
+android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) {
+    switch (dataSpace) {
+        // treat Unknown as regular SRGB buffer, since that's what the rest of the
+        // system expects.
+        case HAL_DATASPACE_UNKNOWN:
+        case HAL_DATASPACE_SRGB:
+        case HAL_DATASPACE_V0_SRGB:
+            return HAL_COLOR_MODE_SRGB;
+            break;
+
+        case HAL_DATASPACE_DISPLAY_P3:
+            return HAL_COLOR_MODE_DISPLAY_P3;
+            break;
+
+        default:
+            // TODO (courtneygo): Do we want to assert an error here?
+            ALOGE("No color mode mapping for %s (%#x)", dataspaceDetails(dataSpace).c_str(),
+                  dataSpace);
+            return HAL_COLOR_MODE_SRGB;
+            break;
+    }
+}
+
+android_dataspace SurfaceFlinger::bestTargetDataSpace(android_dataspace a, android_dataspace b) {
+    // Only support sRGB and Display-P3 right now.
+    if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) {
+        return HAL_DATASPACE_DISPLAY_P3;
+    }
+    return HAL_DATASPACE_V0_SRGB;
+}
+
 void SurfaceFlinger::setUpHWComposer() {
     ATRACE_CALL();
     ALOGV("setUpHWComposer");
@@ -1661,6 +1719,7 @@
     for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
         auto& displayDevice = mDisplays[displayId];
         const auto hwcId = displayDevice->getHwcDisplayId();
+
         if (hwcId < 0) {
             continue;
         }
@@ -1672,6 +1731,21 @@
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             layer->setPerFrameData(displayDevice);
         }
+
+        if (hasWideColorDisplay) {
+            android_color_mode newColorMode;
+            android_dataspace newDataSpace = HAL_DATASPACE_V0_SRGB;
+
+            for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+                newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace);
+                ALOGV("layer: %s, dataspace: %s (%#x), newDataSpace: %s (%#x)",
+                      layer->getName().string(), dataspaceDetails(layer->getDataSpace()).c_str(),
+                      layer->getDataSpace(), dataspaceDetails(newDataSpace).c_str(), newDataSpace);
+            }
+            newColorMode = pickColorMode(newDataSpace);
+
+            setActiveColorModeInternal(displayDevice, newColorMode);
+        }
     }
 
     mPreviousColorMatrix = colorMatrix;
@@ -1950,10 +2024,11 @@
 
                     const wp<IBinder>& display(curr.keyAt(i));
                     if (dispSurface != NULL) {
-                        sp<DisplayDevice> hw = new DisplayDevice(this,
-                                state.type, hwcId, state.isSecure, display,
-                                dispSurface, producer,
-                                mRenderEngine->getEGLConfig());
+                        sp<DisplayDevice> hw =
+                                new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
+                                                  dispSurface, producer,
+                                                  mRenderEngine->getEGLConfig(),
+                                                  hasWideColorDisplay);
                         hw->setLayerStack(state.layerStack);
                         hw->setProjection(state.orientation,
                                 state.viewport, state.frame);
@@ -2369,6 +2444,10 @@
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
+#ifdef USE_HWC2
+        mRenderEngine->setColorMode(displayDevice->getActiveColorMode());
+        mRenderEngine->setWideColor(displayDevice->getWideColorSupport());
+#endif
         if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
                   displayDevice->getDisplayName().string());
@@ -3014,7 +3093,6 @@
     int currentMode = hw->getPowerMode();
 
     if (mode == currentMode) {
-        ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
         return;
     }
 
@@ -3171,6 +3249,12 @@
                 dumpFrameEventsLocked(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) && (args[index] == String16("--wide-color"))) {
+                index++;
+                dumpWideColorInfo(result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
@@ -3341,6 +3425,30 @@
     result.append("\n");
 }
 
+void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
+    result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
+
+    // TODO: print out if wide-color mode is active or not
+
+    for (size_t d = 0; d < mDisplays.size(); d++) {
+        const sp<const DisplayDevice>& displayDevice(mDisplays[d]);
+        int32_t hwcId = displayDevice->getHwcDisplayId();
+        if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
+            continue;
+        }
+
+        result.appendFormat("Display %d color modes:\n", hwcId);
+        std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(hwcId);
+        for (auto&& mode : modes) {
+            result.appendFormat("    %s (%d)\n", decodeColorMode(mode).c_str(), mode);
+        }
+
+        android_color_mode_t currentMode = displayDevice->getActiveColorMode();
+        result.appendFormat("    Current color mode: %s (%d)\n",
+                            decodeColorMode(currentMode).c_str(), currentMode);
+    }
+    result.append("\n");
+}
 
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
         String8& result) const
@@ -3373,6 +3481,9 @@
     appendGuiConfigString(result);
     result.append("\n");
 
+    result.append("\nWide-Color information:\n");
+    dumpWideColorInfo(result);
+
     colorizer.bold(result);
     result.append("Sync configuration: ");
     colorizer.reset(result);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4ecbddd..46121cf 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -151,6 +151,13 @@
     // FramebufferSurface
     static int64_t maxFrameBufferAcquiredBuffers;
 
+    // Indicate if platform supports color management on its
+    // wide-color display. This is typically found on devices
+    // with wide gamut (e.g. Display-P3) display.
+    // This also allows devices with wide-color displays that don't
+    // want to support color management to disable color management.
+    static bool hasWideColorDisplay;
+
     static char const* getServiceName() ANDROID_API {
         return "SurfaceFlinger";
     }
@@ -472,6 +479,12 @@
             nsecs_t vsyncPhase, nsecs_t vsyncInterval,
             nsecs_t compositeToPresentLatency);
     void rebuildLayerStacks();
+
+    // Given a dataSpace, returns the appropriate color_mode to use
+    // to display that dataSpace.
+    android_color_mode pickColorMode(android_dataspace dataSpace);
+    android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b);
+
     void setUpHWComposer();
     void doComposition();
     void doDebugFlashRegions();
@@ -522,6 +535,7 @@
     void recordBufferingStats(const char* layerName,
             std::vector<OccupancyTracker::Segment>&& history);
     void dumpBufferingStats(String8& result) const;
+    void dumpWideColorInfo(String8& result) const;
 
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index a6c0b9c..e640ef7 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -570,7 +570,7 @@
             sp<DisplayDevice> hw = new DisplayDevice(this,
                     type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
                     fbs, producer,
-                    mRenderEngine->getEGLConfig());
+                    mRenderEngine->getEGLConfig(), false);
             if (i > DisplayDevice::DISPLAY_PRIMARY) {
                 // FIXME: currently we don't get blank/unblank requests
                 // for displays other than the main display, so we always
@@ -1740,7 +1740,7 @@
                                 state.type, hwcDisplayId,
                                 mHwc->getFormat(hwcDisplayId), state.isSecure,
                                 display, dispSurface, producer,
-                                mRenderEngine->getEGLConfig());
+                                mRenderEngine->getEGLConfig(), false);
                         hw->setLayerStack(state.layerStack);
                         hw->setProjection(state.orientation,
                                 state.viewport, state.frame);
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index 435aa0c..41b6225 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -1,6 +1,10 @@
 service surfaceflinger /system/bin/surfaceflinger
-    class core
+    class core animation
     user system
     group graphics drmrpc readproc
     onrestart restart zygote
     writepid /dev/stune/foreground/tasks
+    socket pdx/system/vr/display/client stream 0666 system graphics
+    socket pdx/system/vr/display/manager stream 0660 system graphics
+    socket pdx/system/vr/display/screenshot stream 0660 system graphics
+    socket pdx/system/vr/display/vsync stream 0666 system graphics
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index b3d777e..97f0332 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -37,8 +37,6 @@
         libui
 
 include $(CLEAR_VARS)
-# Don't strip symbols so we see stack traces in logcat.
-LOCAL_STRIP_MODULE := false
 LOCAL_SRC_FILES := $(sourceFiles)
 LOCAL_CFLAGS := -DLOG_TAG=\"bufferhubd\"
 LOCAL_CFLAGS += -DTRACE=0
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 80efcf8..2ce60e5 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -16,7 +16,9 @@
 #include "producer_queue_channel.h"
 
 using android::pdx::Channel;
+using android::pdx::ErrorStatus;
 using android::pdx::Message;
+using android::pdx::Status;
 using android::pdx::rpc::DispatchRemoteMethod;
 using android::pdx::default_transport::Endpoint;
 
@@ -28,9 +30,7 @@
 
 BufferHubService::~BufferHubService() {}
 
-bool BufferHubService::IsInitialized() const {
-  return BASE::IsInitialized();
-}
+bool BufferHubService::IsInitialized() const { return BASE::IsInitialized(); }
 
 std::string BufferHubService::DumpState(size_t /*max_length*/) {
   std::ostringstream stream;
@@ -189,7 +189,7 @@
     channel->HandleImpulse(message);
 }
 
-int BufferHubService::HandleMessage(Message& message) {
+pdx::Status<void> BufferHubService::HandleMessage(Message& message) {
   ATRACE_NAME("BufferHubService::HandleMessage");
   auto channel = message.GetChannel<BufferHubChannel>();
 
@@ -207,22 +207,22 @@
     case BufferHubRPC::CreateBuffer::Opcode:
       DispatchRemoteMethod<BufferHubRPC::CreateBuffer>(
           *this, &BufferHubService::OnCreateBuffer, message);
-      return 0;
+      return {};
 
     case BufferHubRPC::CreatePersistentBuffer::Opcode:
       DispatchRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
           *this, &BufferHubService::OnCreatePersistentBuffer, message);
-      return 0;
+      return {};
 
     case BufferHubRPC::GetPersistentBuffer::Opcode:
       DispatchRemoteMethod<BufferHubRPC::GetPersistentBuffer>(
           *this, &BufferHubService::OnGetPersistentBuffer, message);
-      return 0;
+      return {};
 
     case BufferHubRPC::CreateProducerQueue::Opcode:
       DispatchRemoteMethod<BufferHubRPC::CreateProducerQueue>(
           *this, &BufferHubService::OnCreateProducerQueue, message);
-      return 0;
+      return {};
 
     default:
       return DefaultHandleMessage(message);
@@ -374,7 +374,7 @@
   }
 }
 
-int BufferHubService::OnCreateProducerQueue(
+Status<QueueInfo> BufferHubService::OnCreateProducerQueue(
     pdx::Message& message, size_t meta_size_bytes, int usage_set_mask,
     int usage_clear_mask, int usage_deny_set_mask, int usage_deny_clear_mask) {
   // Use the producer channel id as the global queue id.
@@ -386,7 +386,7 @@
   if (const auto channel = message.GetChannel<BufferHubChannel>()) {
     ALOGE("BufferHubService::OnCreateProducerQueue: already created: queue=%d",
           queue_id);
-    return -EALREADY;
+    return ErrorStatus(EALREADY);
   }
 
   int error;
@@ -394,10 +394,10 @@
           this, queue_id, meta_size_bytes, usage_set_mask, usage_clear_mask,
           usage_deny_set_mask, usage_deny_clear_mask, &error)) {
     message.SetChannel(producer_channel);
-    return 0;
+    return {{meta_size_bytes, queue_id}};
   } else {
     ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!");
-    return error;
+    return ErrorStatus(-error);
   }
 }
 
@@ -438,11 +438,11 @@
            "BufferHubChannel::SignalAvailable: channel_id=%d buffer_id=%d",
            channel_id(), buffer_id());
   if (!IsDetached()) {
-    const int ret = service_->ModifyChannelEvents(channel_id_, 0, POLLIN);
-    ALOGE_IF(ret < 0,
+    const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLIN);
+    ALOGE_IF(!status,
              "BufferHubChannel::SignalAvailable: failed to signal availability "
              "channel_id=%d: %s",
-             channel_id_, strerror(-ret));
+             channel_id_, status.GetErrorMessage().c_str());
   } else {
     ALOGD_IF(TRACE, "BufferHubChannel::SignalAvailable: detached buffer.");
   }
@@ -454,11 +454,11 @@
            "BufferHubChannel::ClearAvailable: channel_id=%d buffer_id=%d",
            channel_id(), buffer_id());
   if (!IsDetached()) {
-    const int ret = service_->ModifyChannelEvents(channel_id_, POLLIN, 0);
-    ALOGE_IF(ret < 0,
+    const auto status = service_->ModifyChannelEvents(channel_id_, POLLIN, 0);
+    ALOGE_IF(!status,
              "BufferHubChannel::ClearAvailable: failed to clear availability "
              "channel_id=%d: %s",
-             channel_id_, strerror(-ret));
+             channel_id_, status.GetErrorMessage().c_str());
   } else {
     ALOGD_IF(TRACE, "BufferHubChannel::ClearAvailable: detached buffer.");
   }
@@ -469,11 +469,11 @@
   ALOGD_IF(TRACE, "BufferHubChannel::Hangup: channel_id=%d buffer_id=%d",
            channel_id(), buffer_id());
   if (!IsDetached()) {
-    const int ret = service_->ModifyChannelEvents(channel_id_, 0, POLLHUP);
+    const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLHUP);
     ALOGE_IF(
-        ret < 0,
+        !status,
         "BufferHubChannel::Hangup: failed to signal hangup channel_id=%d: %s",
-        channel_id_, strerror(-ret));
+        channel_id_, status.GetErrorMessage().c_str());
   } else {
     ALOGD_IF(TRACE, "BufferHubChannel::Hangup: detached buffer.");
   }
diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h
index 28cb468..150e399 100644
--- a/services/vr/bufferhubd/buffer_hub.h
+++ b/services/vr/bufferhubd/buffer_hub.h
@@ -7,6 +7,7 @@
 
 #include <hardware/gralloc.h>
 #include <pdx/service.h>
+#include <private/dvr/bufferhub_rpc.h>
 
 namespace android {
 namespace dvr {
@@ -73,9 +74,9 @@
           slice_count(slice_count),
           name(name) {}
 
-    BufferInfo(int id, size_t consumer_count, size_t capacity, int usage_set_mask,
-               int usage_clear_mask, int usage_deny_set_mask,
-               int usage_deny_clear_mask)
+    BufferInfo(int id, size_t consumer_count, size_t capacity,
+               int usage_set_mask, int usage_clear_mask,
+               int usage_deny_set_mask, int usage_deny_clear_mask)
         : id(id),
           type(kProducerQueueType),
           consumer_count(consumer_count),
@@ -141,7 +142,7 @@
   BufferHubService();
   ~BufferHubService() override;
 
-  int HandleMessage(pdx::Message& message) override;
+  pdx::Status<void> HandleMessage(pdx::Message& message) override;
   void HandleImpulse(pdx::Message& message) override;
 
   void OnChannelClose(pdx::Message& message,
@@ -168,9 +169,9 @@
                                int format, int usage, size_t meta_size_bytes,
                                size_t slice_count);
   int OnGetPersistentBuffer(pdx::Message& message, const std::string& name);
-  int OnCreateProducerQueue(pdx::Message& message, size_t meta_size_bytes,
-                            int usage_set_mask, int usage_clear_mask,
-                            int usage_deny_set_mask, int usage_deny_clear_mask);
+  pdx::Status<QueueInfo> OnCreateProducerQueue(
+      pdx::Message& message, size_t meta_size_bytes, int usage_set_mask,
+      int usage_clear_mask, int usage_deny_set_mask, int usage_deny_clear_mask);
 
   BufferHubService(const BufferHubService&) = delete;
   void operator=(const BufferHubService&) = delete;
diff --git a/services/vr/bufferhubd/bufferhubd.rc b/services/vr/bufferhubd/bufferhubd.rc
index 65b7293..8d57723 100644
--- a/services/vr/bufferhubd/bufferhubd.rc
+++ b/services/vr/bufferhubd/bufferhubd.rc
@@ -3,4 +3,4 @@
   user system
   group system
   writepid /dev/cpuset/tasks
-
+  socket pdx/system/buffer_hub/client stream 0660 system system
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp
index ae87acd..cc16f1f 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.cpp
+++ b/services/vr/bufferhubd/consumer_queue_channel.cpp
@@ -40,6 +40,11 @@
           *producer, &ProducerQueueChannel::OnCreateConsumerQueue, message);
       return true;
 
+    case BufferHubRPC::GetQueueInfo::Opcode:
+      DispatchRemoteMethod<BufferHubRPC::GetQueueInfo>(
+          *producer, &ProducerQueueChannel::OnGetQueueInfo, message);
+      return true;
+
     case BufferHubRPC::ConsumerQueueImportBuffers::Opcode:
       DispatchRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>(
           *this, &ConsumerQueueChannel::OnConsumerQueueImportBuffers, message);
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 43010b0..903d174 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -161,12 +161,12 @@
 
   auto consumer = std::make_shared<ConsumerChannel>(
       service(), buffer_id(), channel_id, shared_from_this());
-  const int ret = service()->SetChannel(channel_id, consumer);
-  if (ret < 0) {
+  const auto channel_status = service()->SetChannel(channel_id, consumer);
+  if (!channel_status) {
     ALOGE(
         "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
         "%s",
-        strerror(-ret));
+        channel_status.GetErrorMessage().c_str());
     return RemoteChannelHandle();
   }
 
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp
index 08f1e9d..7741058 100644
--- a/services/vr/bufferhubd/producer_queue_channel.cpp
+++ b/services/vr/bufferhubd/producer_queue_channel.cpp
@@ -3,6 +3,9 @@
 #include "consumer_queue_channel.h"
 #include "producer_channel.h"
 
+using android::pdx::ErrorStatus;
+using android::pdx::Message;
+using android::pdx::Status;
 using android::pdx::RemoteChannelHandle;
 using android::pdx::rpc::DispatchRemoteMethod;
 
@@ -58,6 +61,11 @@
           *this, &ProducerQueueChannel::OnCreateConsumerQueue, message);
       return true;
 
+    case BufferHubRPC::GetQueueInfo::Opcode:
+      DispatchRemoteMethod<BufferHubRPC::GetQueueInfo>(
+          *this, &ProducerQueueChannel::OnGetQueueInfo, message);
+      return true;
+
     case BufferHubRPC::ProducerQueueAllocateBuffers::Opcode:
       DispatchRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>(
           *this, &ProducerQueueChannel::OnProducerQueueAllocateBuffers,
@@ -84,8 +92,8 @@
                     usage_deny_clear_mask_);
 }
 
-std::pair<RemoteChannelHandle, size_t>
-ProducerQueueChannel::OnCreateConsumerQueue(Message& message) {
+Status<RemoteChannelHandle> ProducerQueueChannel::OnCreateConsumerQueue(
+    Message& message) {
   ATRACE_NAME("ProducerQueueChannel::OnCreateConsumerQueue");
   ALOGD_IF(TRACE, "ProducerQueueChannel::OnCreateConsumerQueue: channel_id=%d",
            channel_id());
@@ -97,24 +105,28 @@
         "ProducerQueueChannel::OnCreateConsumerQueue: failed to push consumer "
         "channel: %s",
         status.GetErrorMessage().c_str());
-    REPLY_ERROR_RETURN(message, ENOMEM, {});
+    return ErrorStatus(ENOMEM);
   }
 
-  const int ret = service()->SetChannel(
+  const auto channel_status = service()->SetChannel(
       channel_id, std::make_shared<ConsumerQueueChannel>(
                       service(), buffer_id(), channel_id, shared_from_this()));
-  if (ret < 0) {
+  if (!channel_status) {
     ALOGE(
         "ProducerQueueChannel::OnCreateConsumerQueue: failed to set new "
         "consumer channel: %s",
-        strerror(-ret));
-    REPLY_ERROR_RETURN(message, ENOMEM, {});
+        channel_status.GetErrorMessage().c_str());
+    return ErrorStatus(ENOMEM);
   }
 
-  return std::make_pair(status.take(), meta_size_bytes_);
+  return {status.take()};
 }
 
-std::vector<std::pair<RemoteChannelHandle, size_t>>
+Status<QueueInfo> ProducerQueueChannel::OnGetQueueInfo(Message&) {
+  return {{meta_size_bytes_, buffer_id()}};
+}
+
+Status<std::vector<std::pair<RemoteChannelHandle, size_t>>>
 ProducerQueueChannel::OnProducerQueueAllocateBuffers(Message& message,
                                                      int width, int height,
                                                      int format, int usage,
@@ -135,7 +147,7 @@
         "not permitted. Violating usage_deny_set_mask, the following bits "
         "shall not be set: %d.",
         usage, usage_deny_set_mask_);
-    REPLY_ERROR_RETURN(message, EINVAL, buffer_handles);
+    return ErrorStatus(EINVAL);
   }
 
   if (~usage & usage_deny_clear_mask_) {
@@ -144,7 +156,7 @@
         "not permitted. Violating usage_deny_clear_mask, the following bits "
         "must be set: %d.",
         usage, usage_deny_clear_mask_);
-    REPLY_ERROR_RETURN(message, EINVAL, buffer_handles);
+    return ErrorStatus(EINVAL);
   }
 
   // Force set mask and clear mask. Note that |usage_set_mask_| takes precedence
@@ -152,24 +164,24 @@
   int effective_usage = (usage & ~usage_clear_mask_) | usage_set_mask_;
 
   for (size_t i = 0; i < buffer_count; i++) {
-    auto buffer_handle_slot = AllocateBuffer(message, width, height, format,
-                                             effective_usage, slice_count);
-    if (!buffer_handle_slot.first) {
+    auto status = AllocateBuffer(message, width, height, format,
+                                 effective_usage, slice_count);
+    if (!status) {
       ALOGE(
-          "ProducerQueueChannel::OnProducerQueueAllocateBuffers: failed to "
+          "ProducerQueueChannel::OnProducerQueueAllocateBuffers: Failed to "
           "allocate new buffer.");
-      REPLY_ERROR_RETURN(message, ENOMEM, buffer_handles);
+      return ErrorStatus(status.error());
     }
-    buffer_handles.emplace_back(std::move(buffer_handle_slot.first),
-                                buffer_handle_slot.second);
+    buffer_handles.push_back(status.take());
   }
 
-  return buffer_handles;
+  return {std::move(buffer_handles)};
 }
 
-std::pair<RemoteChannelHandle, size_t> ProducerQueueChannel::AllocateBuffer(
-    Message& message, int width, int height, int format, int usage,
-    size_t slice_count) {
+Status<std::pair<RemoteChannelHandle, size_t>>
+ProducerQueueChannel::AllocateBuffer(Message& message, int width, int height,
+                                     int format, int usage,
+                                     size_t slice_count) {
   ATRACE_NAME("ProducerQueueChannel::AllocateBuffer");
   ALOGD_IF(TRACE,
            "ProducerQueueChannel::AllocateBuffer: producer_channel_id=%d",
@@ -177,7 +189,7 @@
 
   if (capacity_ >= BufferHubRPC::kMaxQueueCapacity) {
     ALOGE("ProducerQueueChannel::AllocateBuffer: reaches kMaxQueueCapacity.");
-    return {};
+    return ErrorStatus(E2BIG);
   }
 
   // Here we are creating a new BufferHubBuffer, initialize the producer
@@ -189,7 +201,7 @@
   if (!status) {
     ALOGE("ProducerQueueChannel::AllocateBuffer: failed to push channel: %s",
           status.GetErrorMessage().c_str());
-    return {};
+    return ErrorStatus(status.error());
   }
 
   ALOGD_IF(TRACE,
@@ -199,14 +211,14 @@
   auto buffer_handle = status.take();
 
   int error;
-  const auto producer_channel = ProducerChannel::Create(
-      service(), buffer_id, width, height, format, usage,
-      meta_size_bytes_, slice_count, &error);
+  const auto producer_channel =
+      ProducerChannel::Create(service(), buffer_id, width, height, format,
+                              usage, meta_size_bytes_, slice_count, &error);
   if (!producer_channel) {
     ALOGE(
         "ProducerQueueChannel::AllocateBuffer: Failed to create "
         "BufferHubBuffer producer!!");
-    return {};
+    return ErrorStatus(ENOMEM);
   }
 
   ALOGD_IF(
@@ -214,13 +226,14 @@
       "ProducerQueueChannel::AllocateBuffer: buffer_id=%d, buffer_handle=%d",
       buffer_id, buffer_handle.value());
 
-  const int ret = service()->SetChannel(buffer_id, producer_channel);
-  if (ret < 0) {
+  const auto channel_status =
+      service()->SetChannel(buffer_id, producer_channel);
+  if (!channel_status) {
     ALOGE(
-        "ProducerQueueChannel::AllocateBuffer: failed to set prodcuer channel "
+        "ProducerQueueChannel::AllocateBuffer: failed to set producer channel "
         "for new BufferHubBuffer: %s",
-        strerror(-ret));
-    return {};
+        channel_status.GetErrorMessage().c_str());
+    return ErrorStatus(ENOMEM);
   }
 
   // Register the newly allocated buffer's channel_id into the first empty
@@ -234,7 +247,7 @@
     ALOGE(
         "ProducerQueueChannel::AllocateBuffer: Cannot find empty slot for new "
         "buffer allocation.");
-    return {};
+    return ErrorStatus(E2BIG);
   }
 
   buffers_[slot] = producer_channel;
@@ -249,29 +262,29 @@
     consumer_channel->RegisterNewBuffer(producer_channel, slot);
   }
 
-  return {std::move(buffer_handle), slot};
+  return {{std::move(buffer_handle), slot}};
 }
 
-int ProducerQueueChannel::OnProducerQueueDetachBuffer(Message& message,
-                                                      size_t slot) {
+Status<void> ProducerQueueChannel::OnProducerQueueDetachBuffer(
+    Message& /*message*/, size_t slot) {
   if (buffers_[slot].expired()) {
     ALOGE(
         "ProducerQueueChannel::OnProducerQueueDetachBuffer: trying to detach "
         "an invalid buffer producer at slot %zu",
         slot);
-    return -EINVAL;
+    return ErrorStatus(EINVAL);
   }
 
   if (capacity_ == 0) {
     ALOGE(
         "ProducerQueueChannel::OnProducerQueueDetachBuffer: trying to detach a "
         "buffer producer while the queue's capacity is already zero.");
-    return -EINVAL;
+    return ErrorStatus(EINVAL);
   }
 
   buffers_[slot].reset();
   capacity_--;
-  return 0;
+  return {};
 }
 
 void ProducerQueueChannel::AddConsumer(ConsumerQueueChannel* channel) {
diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h
index 49611d4..a12a37d 100644
--- a/services/vr/bufferhubd/producer_queue_channel.h
+++ b/services/vr/bufferhubd/producer_queue_channel.h
@@ -3,6 +3,7 @@
 
 #include "buffer_hub.h"
 
+#include <pdx/status.h>
 #include <private/dvr/bufferhub_rpc.h>
 
 namespace android {
@@ -10,17 +11,14 @@
 
 class ProducerQueueChannel : public BufferHubChannel {
  public:
-  using Message = pdx::Message;
-  using RemoteChannelHandle = pdx::RemoteChannelHandle;
-
   static std::shared_ptr<ProducerQueueChannel> Create(
       BufferHubService* service, int channel_id, size_t meta_size_bytes,
       int usage_set_mask, int usage_clear_mask, int usage_deny_set_mask,
       int usage_deny_clear_mask, int* error);
   ~ProducerQueueChannel() override;
 
-  bool HandleMessage(Message& message) override;
-  void HandleImpulse(Message& message) override;
+  bool HandleMessage(pdx::Message& message) override;
+  void HandleImpulse(pdx::Message& message) override;
 
   BufferInfo GetBufferInfo() const override;
 
@@ -28,19 +26,22 @@
   // producer queue.
   // Returns a handle for the service channel, as well as the size of the
   // metadata associated with the queue.
-  std::pair<RemoteChannelHandle, size_t> OnCreateConsumerQueue(
-      Message& message);
+  pdx::Status<pdx::RemoteChannelHandle> OnCreateConsumerQueue(
+      pdx::Message& message);
+
+  pdx::Status<QueueInfo> OnGetQueueInfo(pdx::Message& message);
 
   // Allocate a new BufferHubProducer according to the input spec. Client may
   // handle this as if a new producer is created through kOpCreateBuffer.
-  std::vector<std::pair<RemoteChannelHandle, size_t>>
-  OnProducerQueueAllocateBuffers(Message& message, int width, int height,
+  pdx::Status<std::vector<std::pair<pdx::RemoteChannelHandle, size_t>>>
+  OnProducerQueueAllocateBuffers(pdx::Message& message, int width, int height,
                                  int format, int usage, size_t slice_count,
                                  size_t buffer_count);
 
   // Detach a BufferHubProducer indicated by |slot|. Note that the buffer must
   // be in Gain'ed state for the producer queue to detach.
-  int OnProducerQueueDetachBuffer(Message& message, size_t slot);
+  pdx::Status<void> OnProducerQueueDetachBuffer(pdx::Message& message,
+                                                size_t slot);
 
   void AddConsumer(ConsumerQueueChannel* channel);
   void RemoveConsumer(ConsumerQueueChannel* channel);
@@ -56,10 +57,9 @@
   // and our return type is a RemoteChannelHandle.
   // Returns the remote channdel handle and the slot number for the newly
   // allocated buffer.
-  std::pair<RemoteChannelHandle, size_t> AllocateBuffer(Message& message,
-                                                        int width, int height,
-                                                        int format, int usage,
-                                                        size_t slice_count);
+  pdx::Status<std::pair<pdx::RemoteChannelHandle, size_t>> AllocateBuffer(
+      pdx::Message& message, int width, int height, int format, int usage,
+      size_t slice_count);
 
   // Size of the meta data associated with all the buffers allocated from the
   // queue. Now we assume the metadata size is immutable once the queue is
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 1601c7f..b94d333 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -56,7 +56,7 @@
     "libvr_hwc-binder",
   ],
   shared_libs: [
-    "android.dvr.composer@1.0",
+    "android.frameworks.vr.composer@1.0",
     "android.hardware.graphics.composer@2.1",
     "libbase",
     "libbinder",
@@ -75,31 +75,6 @@
   ],
 }
 
-cc_library_static {
-  name: "libdvr_hwc",
-  srcs: [
-    "dvr_hardware_composer_client.cpp",
-  ],
-  static_libs: [
-    "libvr_hwc-impl",
-    // NOTE: This needs to be included after the *-impl lib otherwise the
-    // symbols in the *-binder library get optimized out.
-    "libvr_hwc-binder",
-  ],
-  shared_libs: [
-    "libbase",
-    "libbinder",
-    "liblog",
-    "libnativewindow",
-    "libui",
-    "libutils",
-  ],
-  export_include_dirs: ["private"],
-  export_shared_lib_headers: [
-    "libnativewindow",
-  ],
-}
-
 cc_test {
   name: "vr_hwc_test",
   gtest: true,
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
index 34e2b7e..999d71e 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
@@ -34,9 +34,9 @@
   // capability. Otherwise assume a count of 1.
   mapper.getLayerCount(handle, &layer_count);
 
-  sp<GraphicBuffer> buffer = new GraphicBuffer(
-      width, height, format, layer_count, producer_usage, consumer_usage,
-      stride, handle, true);
+  sp<GraphicBuffer> buffer = new GraphicBuffer(handle,
+      GraphicBuffer::TAKE_HANDLE, width, height, format, layer_count,
+      producer_usage, consumer_usage, stride);
 
   return buffer;
 }
diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc
index 5d3c4f7..52d4da8 100644
--- a/services/vr/hardware_composer/vr_hwc.rc
+++ b/services/vr/hardware_composer/vr_hwc.rc
@@ -3,4 +3,3 @@
   user system
   group system graphics
   onrestart restart surfaceflinger
-  disabled
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index c99c8d4..955c661 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -170,22 +170,22 @@
   return task.GetCpuSetPath();
 }
 
-int PerformanceService::HandleMessage(Message& message) {
+pdx::Status<void> PerformanceService::HandleMessage(Message& message) {
   switch (message.GetOp()) {
     case PerformanceRPC::SetCpuPartition::Opcode:
       DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>(
           *this, &PerformanceService::OnSetCpuPartition, message);
-      return 0;
+      return {};
 
     case PerformanceRPC::SetSchedulerClass::Opcode:
       DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>(
           *this, &PerformanceService::OnSetSchedulerClass, message);
-      return 0;
+      return {};
 
     case PerformanceRPC::GetCpuPartition::Opcode:
       DispatchRemoteMethod<PerformanceRPC::GetCpuPartition>(
           *this, &PerformanceService::OnGetCpuPartition, message);
-      return 0;
+      return {};
 
     default:
       return Service::HandleMessage(message);
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index e32d834..34abba7 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -17,7 +17,7 @@
 // achieve system performance goals.
 class PerformanceService : public pdx::ServiceBase<PerformanceService> {
  public:
-  int HandleMessage(pdx::Message& message) override;
+  pdx::Status<void> HandleMessage(pdx::Message& message) override;
   bool IsInitialized() const override;
 
   std::string DumpState(size_t max_length) override;
diff --git a/services/vr/performanced/performanced.rc b/services/vr/performanced/performanced.rc
index 5042982..6283f37 100644
--- a/services/vr/performanced/performanced.rc
+++ b/services/vr/performanced/performanced.rc
@@ -3,3 +3,4 @@
   user root
   group system readproc
   writepid /dev/cpuset/tasks
+  socket pdx/system/performance/client stream 0666 system system
diff --git a/services/vr/sensord/Android.mk b/services/vr/sensord/Android.mk
index ba0821b..638c9a8 100644
--- a/services/vr/sensord/Android.mk
+++ b/services/vr/sensord/Android.mk
@@ -51,8 +51,6 @@
           -DTRACE=0
 
 include $(CLEAR_VARS)
-# Don't strip symbols so we see stack traces in logcat.
-LOCAL_STRIP_MODULE := false
 LOCAL_SRC_FILES := $(sourceFiles)
 LOCAL_CFLAGS := $(cFlags)
 LOCAL_STATIC_LIBRARIES := $(staticLibraries)
diff --git a/services/vr/sensord/pose_service.cpp b/services/vr/sensord/pose_service.cpp
index 2c4fc30..e3f8171 100644
--- a/services/vr/sensord/pose_service.cpp
+++ b/services/vr/sensord/pose_service.cpp
@@ -65,6 +65,8 @@
 static constexpr int kDatasetIdLength = 36;
 static constexpr char kDatasetIdChars[] = "0123456789abcdef-";
 
+static constexpr int kLatencyWindowSize = 200;
+
 // These are the flags used by BufferProducer::CreatePersistentUncachedBlob,
 // plus PRIVATE_ADSP_HEAP to allow access from the DSP.
 static constexpr int kPoseRingBufferFlags =
@@ -111,7 +113,8 @@
       vsync_count_(0),
       photon_timestamp_(0),
       // Will be updated by external service, but start with a non-zero value:
-      display_period_ns_(16000000) {
+      display_period_ns_(16000000),
+      sensor_latency_(kLatencyWindowSize) {
   last_known_pose_ = {
       .orientation = {1.0f, 0.0f, 0.0f, 0.0f},
       .translation = {0.0f, 0.0f, 0.0f, 0.0f},
@@ -463,10 +466,13 @@
           start_from_head_rotation * Vector3d(0.0, kDefaultNeckVerticalOffset,
                                               -kDefaultNeckHorizontalOffset);
 
-      // IMU driver gives timestamps on its own clock, but we need monotonic
-      // clock. Subtract 5ms to account for estimated IMU sample latency.
-      WriteAsyncPoses(position, start_from_head_rotation,
-                      pose_state.timestamp_ns + 5000000);
+      // Update the current latency model.
+      sensor_latency_.AddLatency(GetSystemClockNs() - pose_state.timestamp_ns);
+
+      // Update the timestamp with the expected latency.
+      WriteAsyncPoses(
+          position, start_from_head_rotation,
+          pose_state.timestamp_ns + sensor_latency_.CurrentLatencyEstimate());
       break;
     }
     default:
@@ -476,8 +482,8 @@
   }
 }
 
-int PoseService::HandleMessage(pdx::Message& msg) {
-  int ret = 0;
+pdx::Status<void> PoseService::HandleMessage(pdx::Message& msg) {
+  pdx::Status<void> ret;
   const pdx::MessageInfo& info = msg.GetInfo();
   switch (info.op) {
     case DVR_POSE_NOTIFY_VSYNC: {
@@ -495,21 +501,13 @@
           {.iov_base = &right_eye_photon_offset_ns_,
            .iov_len = sizeof(right_eye_photon_offset_ns_)},
       };
-      constexpr int expected_size =
-          sizeof(vsync_count_) + sizeof(photon_timestamp_) +
-          sizeof(display_period_ns_) + sizeof(right_eye_photon_offset_ns_);
-      ret = msg.ReadVector(data, sizeof(data) / sizeof(data[0]));
-      if (ret < expected_size) {
-        ALOGI("error: msg.Read read too little (%d < %d)", ret, expected_size);
-        REPLY_ERROR(msg, EIO, error);
-      }
-
-      if (!enable_external_pose_) {
+      ret = msg.ReadVectorAll(data);
+      if (ret && !enable_external_pose_) {
         mapped_pose_buffer_->vsync_count = vsync_count_;
       }
 
       // TODO(jbates, eieio): make this async, no need to reply.
-      REPLY_SUCCESS(msg, 0, error);
+      REPLY_MESSAGE(msg, ret, error);
     }
     case DVR_POSE_POLL: {
       ATRACE_NAME("pose_poll");
@@ -535,61 +533,43 @@
 
       Btrace("Pose polled");
 
-      ret = msg.Write(&client_state, sizeof(client_state));
-      const int expected_size = sizeof(client_state);
-      if (ret < expected_size) {
-        ALOGI("error: msg.Write wrote too little (%d < %d)", ret,
-              expected_size);
-        REPLY_ERROR(msg, EIO, error);
-      }
-      REPLY_SUCCESS(msg, 0, error);
+      ret = msg.WriteAll(&client_state, sizeof(client_state));
+      REPLY_MESSAGE(msg, ret, error);
     }
     case DVR_POSE_FREEZE: {
       {
         std::lock_guard<std::mutex> guard(mutex_);
 
         DvrPoseState frozen_state;
-        const int expected_size = sizeof(frozen_state);
-        ret = msg.Read(&frozen_state, expected_size);
-        if (ret < expected_size) {
-          ALOGI("error: msg.Read read too little (%d < %d)", ret,
-                expected_size);
-          REPLY_ERROR(msg, EIO, error);
+        ret = msg.ReadAll(&frozen_state, sizeof(frozen_state));
+        if (!ret) {
+          REPLY_ERROR(msg, ret.error(), error);
         }
         frozen_state_ = frozen_state;
       }
       SetPoseMode(DVR_POSE_MODE_MOCK_FROZEN);
-      REPLY_SUCCESS(msg, 0, error);
+      REPLY_MESSAGE(msg, ret, error);
     }
     case DVR_POSE_SET_MODE: {
       int mode;
       {
         std::lock_guard<std::mutex> guard(mutex_);
-        const int expected_size = sizeof(mode);
-        ret = msg.Read(&mode, expected_size);
-        if (ret < expected_size) {
-          ALOGI("error: msg.Read read too little (%d < %d)", ret,
-                expected_size);
-          REPLY_ERROR(msg, EIO, error);
+        ret = msg.ReadAll(&mode, sizeof(mode));
+        if (!ret) {
+          REPLY_ERROR(msg, ret.error(), error);
         }
         if (mode < 0 || mode >= DVR_POSE_MODE_COUNT) {
           REPLY_ERROR(msg, EINVAL, error);
         }
       }
       SetPoseMode(DvrPoseMode(mode));
-      REPLY_SUCCESS(msg, 0, error);
+      REPLY_MESSAGE(msg, ret, error);
     }
     case DVR_POSE_GET_MODE: {
       std::lock_guard<std::mutex> guard(mutex_);
       int mode = pose_mode_;
-      ret = msg.Write(&mode, sizeof(mode));
-      const int expected_size = sizeof(mode);
-      if (ret < expected_size) {
-        ALOGI("error: msg.Write wrote too little (%d < %d)", ret,
-              expected_size);
-        REPLY_ERROR(msg, EIO, error);
-      }
-      REPLY_SUCCESS(msg, 0, error);
+      ret = msg.WriteAll(&mode, sizeof(mode));
+      REPLY_MESSAGE(msg, ret, error);
     }
     case DVR_POSE_GET_RING_BUFFER: {
       std::lock_guard<std::mutex> guard(mutex_);
diff --git a/services/vr/sensord/pose_service.h b/services/vr/sensord/pose_service.h
index 4df5036..7b7adec 100644
--- a/services/vr/sensord/pose_service.h
+++ b/services/vr/sensord/pose_service.h
@@ -11,8 +11,9 @@
 #include <dvr/pose_client.h>
 #include <pdx/service.h>
 #include <private/dvr/buffer_hub_client.h>
-#include <private/dvr/pose_client_internal.h>
 #include <private/dvr/dvr_pose_predictor.h>
+#include <private/dvr/latency_model.h>
+#include <private/dvr/pose_client_internal.h>
 #include <private/dvr/ring_buffer.h>
 
 #include "sensor_fusion.h"
@@ -27,7 +28,7 @@
   ~PoseService() override;
 
   bool IsInitialized() const override;
-  int HandleMessage(pdx::Message& msg) override;
+  pdx::Status<void> HandleMessage(pdx::Message& msg) override;
   std::string DumpState(size_t max_length) override;
 
   // Handle events from the sensor HAL.
@@ -132,6 +133,9 @@
   int64_t display_period_ns_;
   int64_t right_eye_photon_offset_ns_ = 0;
 
+  // To model the measurement - arrival latency.
+  LatencyModel sensor_latency_;
+
   // Type for controlling pose orientation calculation.
   OrientationType device_orientation_type_;
 
diff --git a/services/vr/sensord/sensor_service.cpp b/services/vr/sensord/sensor_service.cpp
index 1b809b0..a182a26 100644
--- a/services/vr/sensord/sensor_service.cpp
+++ b/services/vr/sensord/sensor_service.cpp
@@ -69,8 +69,8 @@
   client->unset_sensor();
 }
 
-int SensorService::HandleMessage(pdx::Message& msg) {
-  int ret = 0;
+pdx::Status<void> SensorService::HandleMessage(pdx::Message& msg) {
+  pdx::Status<void> ret;
   const pdx::MessageInfo& info = msg.GetInfo();
   switch (info.op) {
     case DVR_SENSOR_START: {
@@ -82,8 +82,7 @@
       if (client->has_sensor())
         REPLY_ERROR(msg, EINVAL, error);
       int sensor_type;
-      if (msg.Read(&sensor_type, sizeof(sensor_type)) <
-          (ssize_t)sizeof(sensor_type))
+      if (!msg.ReadAll(&sensor_type, sizeof(sensor_type)))
         REPLY_ERROR(msg, EIO, error);
 
       // Find the sensor of the requested type.
@@ -120,10 +119,8 @@
           {.iov_base = out_buffer,
            .iov_len = num_events * sizeof(sensors_event_t)},
       };
-      ret = msg.WriteVector(svec, 2);
-      int expected_size = sizeof(int) + num_events * sizeof(sensors_event_t);
-      if (ret < expected_size) {
-        ALOGI("error: msg.WriteVector wrote too little.");
+      ret = msg.WriteVectorAll(svec, 2);
+      if (!ret) {
         REPLY_ERROR(msg, EIO, error);
       }
       REPLY_SUCCESS(msg, 0, error);
diff --git a/services/vr/sensord/sensor_service.h b/services/vr/sensord/sensor_service.h
index c35fada..6ea470b 100644
--- a/services/vr/sensord/sensor_service.h
+++ b/services/vr/sensord/sensor_service.h
@@ -22,7 +22,7 @@
  */
 class SensorService : public pdx::ServiceBase<SensorService> {
  public:
-  int HandleMessage(pdx::Message& msg) override;
+  pdx::Status<void> HandleMessage(pdx::Message& msg) override;
   std::shared_ptr<pdx::Channel> OnChannelOpen(pdx::Message& msg) override;
   void OnChannelClose(pdx::Message& msg,
                       const std::shared_ptr<pdx::Channel>& chan) override;
diff --git a/services/vr/sensord/sensord.rc b/services/vr/sensord/sensord.rc
index f8d28fd..36cd377 100644
--- a/services/vr/sensord/sensord.rc
+++ b/services/vr/sensord/sensord.rc
@@ -7,3 +7,5 @@
   user system
   group system camera sdcard_rw
   writepid /dev/cpuset/system/tasks
+  socket pdx/system/vr/sensors/client stream 0666 system system
+  socket pdx/system/vr/pose/client stream 0666 system system
diff --git a/services/vr/virtual_touchpad/main.cpp b/services/vr/virtual_touchpad/main.cpp
index 68f1d70..55ac9bf 100644
--- a/services/vr/virtual_touchpad/main.cpp
+++ b/services/vr/virtual_touchpad/main.cpp
@@ -8,8 +8,9 @@
 
 int main() {
   ALOGI("Starting");
-  android::dvr::VirtualTouchpadService touchpad_service(
-      std::move(android::dvr::VirtualTouchpadEvdev::Create()));
+  android::sp<android::dvr::VirtualTouchpadService> touchpad_service =
+      new android::dvr::VirtualTouchpadService(
+          android::dvr::VirtualTouchpadEvdev::Create());
 
   signal(SIGPIPE, SIG_IGN);
   android::sp<android::ProcessState> ps(android::ProcessState::self());
@@ -19,8 +20,8 @@
 
   android::sp<android::IServiceManager> sm(android::defaultServiceManager());
   const android::status_t service_status =
-      sm->addService(android::String16(touchpad_service.SERVICE_NAME()),
-                     &touchpad_service, false /*allowIsolated*/);
+      sm->addService(android::String16(touchpad_service->SERVICE_NAME()),
+                     touchpad_service, false /*allowIsolated*/);
   if (service_status != android::OK) {
     ALOGE("virtual touchpad service not added: %d",
           static_cast<int>(service_status));
diff --git a/services/vr/vr_window_manager/Android.bp b/services/vr/vr_window_manager/Android.bp
index a7a341c..669426b 100644
--- a/services/vr/vr_window_manager/Android.bp
+++ b/services/vr/vr_window_manager/Android.bp
@@ -41,12 +41,13 @@
     "libperformance",
     "libpdx_default_transport",
     "libcutils",
+    "libvr_hwc-binder",
     "libvr_manager",
     "libvirtualtouchpadclient",
 ]
 
 shared_libs = [
-    "android.dvr.composer@1.0",
+    "android.frameworks.vr.composer@1.0",
     "android.hardware.graphics.composer@2.1",
     "libvrhwc",
     "libbase",
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index b2f02e5..8b4460a 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -206,8 +206,9 @@
     if (fade_value_ > 1.0f)
       fade_value_ = 1.0f;
 
-    controller_position_ = elbow_model_.Update(delta, last_pose_.GetRotation(),
-                                               controller_orientation_, false);
+    controller_position_ =
+        elbow_model_.Update(delta, last_pose_.GetRotation(),
+                            controller_orientation_, should_recenter_);
 
     dvrBeginRenderFrameEds(graphics_context_, pose.orientation,
                            pose.translation);
@@ -233,6 +234,7 @@
     OnEndFrame();
 
     dvrPresent(graphics_context_);
+    should_recenter_ = false;
   }
 }
 
diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h
index 4b36ecc..ed99157 100644
--- a/services/vr/vr_window_manager/application.h
+++ b/services/vr/vr_window_manager/application.h
@@ -80,6 +80,9 @@
   bool shmem_controller_active_ = false;
   uint64_t shmem_controller_buttons_;
 
+  // Used to center the scene when the shell becomes visible.
+  bool should_recenter_ = true;
+
   bool is_visible_ = false;
   std::chrono::time_point<std::chrono::system_clock> visibility_button_press_;
   bool debug_mode_ = false;
diff --git a/services/vr/vr_window_manager/composer/1.0/Android.bp b/services/vr/vr_window_manager/composer/1.0/Android.bp
deleted file mode 100644
index 58f83f8..0000000
--- a/services/vr/vr_window_manager/composer/1.0/Android.bp
+++ /dev/null
@@ -1,54 +0,0 @@
-// This file is autogenerated by hidl-gen. Do not edit manually.
-
-genrule {
-    name: "android.dvr.composer@1.0_genc++",
-    tools: ["hidl-gen"],
-    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hidl:system/libhidl/transport -randroid.hardware:hardware/interfaces/ -randroid.dvr:frameworks/native/services/vr/vr_window_manager android.dvr.composer@1.0",
-    srcs: [
-        "IVrComposerClient.hal",
-    ],
-    out: [
-        "android/dvr/composer/1.0/VrComposerClientAll.cpp",
-    ],
-}
-
-genrule {
-    name: "android.dvr.composer@1.0_genc++_headers",
-    tools: ["hidl-gen"],
-    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hidl:system/libhidl/transport -randroid.hardware:hardware/interfaces/ -randroid.dvr:frameworks/native/services/vr/vr_window_manager android.dvr.composer@1.0",
-    srcs: [
-        "IVrComposerClient.hal",
-    ],
-    out: [
-        "android/dvr/composer/1.0/IVrComposerClient.h",
-        "android/dvr/composer/1.0/IHwVrComposerClient.h",
-        "android/dvr/composer/1.0/BnHwVrComposerClient.h",
-        "android/dvr/composer/1.0/BpHwVrComposerClient.h",
-        "android/dvr/composer/1.0/BsVrComposerClient.h",
-    ],
-}
-
-cc_library_shared {
-    name: "android.dvr.composer@1.0",
-    generated_sources: ["android.dvr.composer@1.0_genc++"],
-    generated_headers: ["android.dvr.composer@1.0_genc++_headers"],
-    export_generated_headers: ["android.dvr.composer@1.0_genc++_headers"],
-    shared_libs: [
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "liblog",
-        "libutils",
-        "libcutils",
-        "android.hardware.graphics.composer@2.1",
-        "android.hidl.base@1.0",
-    ],
-    export_shared_lib_headers: [
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "libutils",
-        "android.hardware.graphics.composer@2.1",
-        "android.hidl.base@1.0",
-    ],
-}
diff --git a/services/vr/vr_window_manager/composer/1.0/IVrComposerClient.hal b/services/vr/vr_window_manager/composer/1.0/IVrComposerClient.hal
deleted file mode 100644
index 230a68a..0000000
--- a/services/vr/vr_window_manager/composer/1.0/IVrComposerClient.hal
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-package android.dvr.composer@1.0;
-
-import android.hardware.graphics.composer@2.1::IComposerClient;
-
-interface IVrComposerClient
-    extends android.hardware.graphics.composer@2.1::IComposerClient {
-    /*
-     * Used to annotate the layer with additional information, which will be
-     * used to describe the content of the layer (ie: notification, permission,
-     * etc) which allows VR window manager to treat certain layer types
-     * specially.
-     *
-     * @param display is the display on which the layer was created.
-     * @param layer is the layer affected by the change.
-     * @param layer_type the type of the layer as described by the window
-     * manager.
-     * @param application_id the application id the layer belongs to.
-     * @return error is NONE upon success. Otherwise,
-     *         BAD_DISPLAY when an invalid display handle was passed in.
-     *         BAD_LAYER when an invalid layer handle was passed in.
-     *
-     * setLayerInfo(Display display,
-     *              Layer layer,
-     *              uint32_t layer_type,
-     *              uint32_t application_id)
-     *     generates(Error error);
-     */
-
-    enum VrCommand : int32_t {
-        OPCODE_SHIFT         = android.hardware.graphics.composer@2.1::IComposerClient.Command:OPCODE_SHIFT,
-
-        SET_LAYER_INFO = 0x800 << OPCODE_SHIFT,
-    };
-};
diff --git a/services/vr/vr_window_manager/composer/Android.bp b/services/vr/vr_window_manager/composer/Android.bp
index f28818a..007251f 100644
--- a/services/vr/vr_window_manager/composer/Android.bp
+++ b/services/vr/vr_window_manager/composer/Android.bp
@@ -1,7 +1,3 @@
-subdirs = [
-  "1.0",
-]
-
 cc_library_shared {
   name: "libvrhwc",
 
@@ -20,7 +16,7 @@
   ],
 
   shared_libs: [
-    "android.dvr.composer@1.0",
+    "android.frameworks.vr.composer@1.0",
     "android.hardware.graphics.composer@2.1",
     "libbase",
     "libcutils",
diff --git a/services/vr/vr_window_manager/composer/impl/vr_composer_client.cpp b/services/vr/vr_window_manager/composer/impl/vr_composer_client.cpp
index 367acb7..acf0dac 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_composer_client.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_composer_client.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <android/dvr/composer/1.0/IVrComposerClient.h>
+#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
 #include <hardware/gralloc.h>
 #include <hardware/gralloc1.h>
 #include <log/log.h>
@@ -26,7 +26,7 @@
 namespace dvr {
 
 using android::hardware::graphics::common::V1_0::PixelFormat;
-using android::dvr::composer::V1_0::IVrComposerClient;
+using android::frameworks::vr::composer::V1_0::IVrComposerClient;
 
 VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
     : ComposerClient(hal), mVrHal(hal) {}
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index 3393ade..9ba01f9 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -49,12 +49,6 @@
   int32_t format = 0;
 
   GraphicBufferMapper& mapper = GraphicBufferMapper::get();
-  // Need to register |handle| otherwise we can't read its properties.
-  if (mapper.registerBuffer(handle) != OK) {
-    ALOGE("Failed to register buffer");
-    return nullptr;
-  }
-
   if (mapper.getDimensions(handle, &width, &height) ||
       mapper.getStride(handle, &stride) ||
       mapper.getFormat(handle, &format) ||
@@ -69,11 +63,10 @@
   mapper.getLayerCount(handle, &layer_count);
 
   // NOTE: Can't re-use |handle| since we don't own it.
-  sp<GraphicBuffer> buffer = new GraphicBuffer(
-      width, height, format, layer_count, producer_usage, consumer_usage,
-      stride, native_handle_clone(handle), true);
-  // Need to register the cloned buffer otherwise it can't be used later on.
-  if (mapper.registerBuffer(buffer.get()) != OK) {
+  sp<GraphicBuffer> buffer = new GraphicBuffer(handle,
+      GraphicBuffer::CLONE_HANDLE, width, height, format, layer_count,
+      producer_usage, consumer_usage, stride);
+  if (buffer->initCheck() != OK) {
     ALOGE("Failed to register cloned buffer");
     return nullptr;
   }
@@ -218,19 +211,14 @@
       queued_client_target = true;
     } else {
       if (!layer.info.buffer.get() || !layer.info.fence.get()) {
-        ALOGE("Layer requested without valid buffer");
-        return Error::BAD_LAYER;
+        ALOGV("Layer requested without valid buffer");
+        continue;
       }
 
       frame.push_back(layer.info);
     }
   }
 
-  if (frame.empty()) {
-    ALOGE("Requested frame with no layers");
-    return Error::BAD_LAYER;
-  }
-
   out_frames->swap(frame);
   return Error::NONE;
 }
diff --git a/services/vr/vr_window_manager/display_view.cpp b/services/vr/vr_window_manager/display_view.cpp
index 52984b7..88768a0 100644
--- a/services/vr/vr_window_manager/display_view.cpp
+++ b/services/vr/vr_window_manager/display_view.cpp
@@ -219,6 +219,11 @@
       visibility = ViewMode::Hidden;
       current_vr_app_ = app;
     }
+  } else if ((use_2dmode_ || !is_vr_active) && app != 0 &&
+             visibility == ViewMode::Hidden) {
+    // This is the case for the VR app launching a 2D intent of itself on some
+    // display.
+    visibility = ViewMode::App;
   } else if (!current_vr_app_) {
     // The VR app is running.
     current_vr_app_ = app;
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index 19b220b..43f5042 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -38,26 +38,29 @@
 HwcCallback::~HwcCallback() {
 }
 
-base::unique_fd HwcCallback::OnNewFrame(const ComposerView::Frame& display_frame) {
-  auto& frame = display_frame.layers;
-  std::vector<HwcLayer> hwc_frame(frame.size());
-
-  for (size_t i = 0; i < frame.size(); ++i) {
+binder::Status HwcCallback::onNewFrame(
+    const ParcelableComposerFrame& parcelable_frame,
+    ParcelableUniqueFd* fence) {
+  ComposerView::Frame frame = parcelable_frame.frame();
+  std::vector<HwcLayer> hwc_frame(frame.layers.size());
+  for (size_t i = 0; i < frame.layers.size(); ++i) {
+    const ComposerView::ComposerLayer& layer = frame.layers[i];
     hwc_frame[i] = HwcLayer{
-      .fence = frame[i].fence,
-      .buffer = frame[i].buffer,
-      .crop = frame[i].crop,
-      .display_frame = frame[i].display_frame,
-      .blending = static_cast<int32_t>(frame[i].blend_mode),
-      .appid = frame[i].app_id,
-      .type = static_cast<HwcLayer::LayerType>(frame[i].type),
-      .alpha = frame[i].alpha,
+      .fence = layer.fence,
+      .buffer = layer.buffer,
+      .crop = layer.crop,
+      .display_frame = layer.display_frame,
+      .blending = static_cast<int32_t>(layer.blend_mode),
+      .appid = layer.app_id,
+      .type = static_cast<HwcLayer::LayerType>(layer.type),
+      .alpha = layer.alpha,
     };
   }
 
-  return client_->OnFrame(std::make_unique<Frame>(
-      std::move(hwc_frame), display_frame.display_id, display_frame.removed,
-      display_frame.display_width, display_frame.display_height));
+  fence->set_fence(client_->OnFrame(std::make_unique<Frame>(
+      std::move(hwc_frame), frame.display_id, frame.removed,
+      frame.display_width, frame.display_height)));
+  return binder::Status::ok();
 }
 
 HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers, uint32_t display_id,
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index c0d965a..f1f91a1 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -1,14 +1,16 @@
 #ifndef VR_WINDOW_MANAGER_HWC_CALLBACK_H_
 #define VR_WINDOW_MANAGER_HWC_CALLBACK_H_
 
+#include <android/dvr/BnVrComposerCallback.h>
+#include <android-base/unique_fd.h>
+
 #include <deque>
 #include <functional>
 #include <mutex>
 #include <vector>
 
-#include <android-base/unique_fd.h>
-#include <impl/vr_composer_view.h>
-#include <impl/vr_hwc.h>
+#include "impl/vr_composer_view.h"
+#include "impl/vr_hwc.h"
 
 namespace android {
 
@@ -20,7 +22,7 @@
 using Recti = ComposerView::ComposerLayer::Recti;
 using Rectf = ComposerView::ComposerLayer::Rectf;
 
-class HwcCallback : public VrComposerView::Callback {
+class HwcCallback : public BnVrComposerCallback {
  public:
   struct HwcLayer {
     enum LayerType : uint32_t {
@@ -110,7 +112,8 @@
   ~HwcCallback() override;
 
  private:
-  base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
+  binder::Status onNewFrame(const ParcelableComposerFrame& frame,
+                            ParcelableUniqueFd* fence) override;
 
   Client *client_;
 
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 850f604..2b53cd6 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -327,7 +327,6 @@
     // Position the quad horizontally aligned in the direction the user
     // is facing, effectively taking out head roll.
     displays_[0]->Recenter(GetHorizontallyAlignedMatrixFromPose(last_pose_));
-    should_recenter_ = false;
   }
 
   for (auto& display : displays_) {
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index be2ae58..d90e833 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -84,9 +84,6 @@
   bool is_touching_ = false;
   int touchpad_buttons_ = 0;
 
-  // Used to center the scene when the shell becomes visible.
-  bool should_recenter_ = true;
-
   std::mutex display_frame_mutex_;
 
   std::vector<std::unique_ptr<DisplayView>> displays_;
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index c0ee1fc..aef23a1 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -1,5 +1,7 @@
 #include "surface_flinger_view.h"
 
+#include <android/dvr/IVrComposer.h>
+#include <binder/IServiceManager.h>
 #include <impl/vr_composer_view.h>
 #include <private/dvr/native_buffer.h>
 
@@ -14,22 +16,20 @@
 SurfaceFlingerView::~SurfaceFlingerView() {}
 
 bool SurfaceFlingerView::Initialize(HwcCallback::Client *client) {
-  const char vr_hwcomposer_name[] = "vr";
-  vr_hwcomposer_ = HIDL_FETCH_IComposer(vr_hwcomposer_name);
-  if (!vr_hwcomposer_.get()) {
-    ALOGE("Failed to get vr_hwcomposer");
+  sp<IServiceManager> sm(defaultServiceManager());
+  vr_composer_ = interface_cast<IVrComposer>(
+      sm->getService(IVrComposer::SERVICE_NAME()));
+
+  String8 service_name(IVrComposer::SERVICE_NAME().string());
+  if (!vr_composer_.get()) {
+    ALOGE("Faild to connect to %s", service_name.c_str());
     return false;
   }
 
-  if (vr_hwcomposer_->isRemote()) {
-    ALOGE("vr_hwcomposer service is remote");
-    return false;
-  }
-
-  const android::status_t vr_hwcomposer_status =
-      vr_hwcomposer_->registerAsService(vr_hwcomposer_name);
-  if (vr_hwcomposer_status != OK) {
-    ALOGE("Failed to register vr_hwcomposer service");
+  composer_callback_ = new HwcCallback(client);
+  binder::Status status = vr_composer_->registerObserver(composer_callback_);
+  if (!status.isOk()) {
+    ALOGE("Failed to register observer with %s", service_name.c_str());
     return false;
   }
 
diff --git a/services/vr/vr_window_manager/surface_flinger_view.h b/services/vr/vr_window_manager/surface_flinger_view.h
index 3ea2b21..1bea38d 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.h
+++ b/services/vr/vr_window_manager/surface_flinger_view.h
@@ -3,14 +3,13 @@
 
 #include <memory>
 
-#include <impl/vr_composer_view.h>
-
 #include "hwc_callback.h"
 
 namespace android {
 namespace dvr {
 
 class IDisplay;
+class IVrComposer;
 class Texture;
 
 struct TextureLayer {
@@ -34,8 +33,8 @@
                    bool skip_first_layer) const;
 
  private:
-  sp<IComposer> vr_hwcomposer_;
-  std::unique_ptr<VrComposerView> vr_composer_view_;
+  sp<IVrComposer> vr_composer_;
+  sp<HwcCallback> composer_callback_;
 
   SurfaceFlingerView(const SurfaceFlingerView&) = delete;
   void operator=(const SurfaceFlingerView&) = delete;
diff --git a/services/vr/vr_window_manager/vr_window_manager.cpp b/services/vr/vr_window_manager/vr_window_manager.cpp
index 6636dc5..9d7afe3 100644
--- a/services/vr/vr_window_manager/vr_window_manager.cpp
+++ b/services/vr/vr_window_manager/vr_window_manager.cpp
@@ -20,20 +20,20 @@
   LOG_ALWAYS_FATAL_IF(app_status != 0, "failed to initialize: %d", app_status);
 
   // Create vr_wm_binder.
-  android::service::vr::VrWindowManagerBinder vr_wm_binder(app);
-  const int status = vr_wm_binder.Initialize();
+  android::sp<android::service::vr::VrWindowManagerBinder> vr_wm_binder =
+      new android::service::vr::VrWindowManagerBinder(app);
+  const int status = vr_wm_binder->Initialize();
   LOG_ALWAYS_FATAL_IF(status != 0, "initialization failed: %d", status);
 
   android::sp<android::IServiceManager> sm(android::defaultServiceManager());
-  const android::status_t vr_wm_binder_status =
-      sm->addService(
-          android::service::vr::VrWindowManagerBinder::SERVICE_NAME(),
-          &vr_wm_binder, false /*allowIsolated*/);
+  const android::status_t vr_wm_binder_status = sm->addService(
+      android::service::vr::VrWindowManagerBinder::SERVICE_NAME(),
+      vr_wm_binder, false /*allowIsolated*/);
   LOG_ALWAYS_FATAL_IF(vr_wm_binder_status != android::OK,
                       "vr_wm_binder service not added: %d",
                       static_cast<int>(vr_wm_binder_status));
 
-  app.SetControllerDataProvider(&vr_wm_binder);
+  app.SetControllerDataProvider(vr_wm_binder.get());
 
   android::hardware::ProcessState::self()->startThreadPool();
 
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 86dd001..a19fcf1 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
 define VERSION_MINOR 0
-define VERSION_PATCH 43
+define VERSION_PATCH 46
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -93,7 +93,7 @@
 @extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME             "VK_ANDROID_native_buffer"
 
 // 12
-@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION       5
+@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION       6
 @extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME               "VK_EXT_debug_report"
 
 // 13
@@ -250,7 +250,7 @@
 
 // 85
 @extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
-@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_NAME "VK_KHR_incremental_present"
+@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"
 
 // 86
 @extension("VK_KHR_descriptor_update_template") define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1
@@ -309,8 +309,8 @@
 @extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles"
 
 // 105
-@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 1
-@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_COUNTER_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
+@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 2
+@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
 
 // 106
 @extension("VK_EXT_hdr_metadata") define VK_EXT_HDR_METADATA_SPEC_VERSION 1
@@ -1195,19 +1195,20 @@
 enum VkColorSpaceKHR {
     VK_COLORSPACE_SRGB_NONLINEAR_KHR                        = 0x00000000,
 
-    //@extension("VK_EXT_swapchain_colorspace")
-    VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT                    = 1000104001,
-    VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT                 = 1000104002,
-    VK_COLOR_SPACE_SCRGB_LINEAR_EXT                         = 1000104003,
-    VK_COLOR_SPACE_SCRGB_NONLINEAR_EXT                      = 1000104004,
-    VK_COLOR_SPACE_DCI_P3_LINEAR_EXT                        = 1000104005,
-    VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT                     = 1000104006,
-    VK_COLOR_SPACE_BT709_LINEAR_EXT                         = 1000104007,
-    VK_COLOR_SPACE_BT709_NONLINEAR_EXT                      = 1000104008,
-    VK_COLOR_SPACE_BT2020_LINEAR_EXT                        = 1000104009,
-    VK_COLOR_SPACE_BT2020_NONLINEAR_EXT                     = 1000104010,
+    //@extension("VK_EXT_swapchain_colorspace") // 105
+    VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT                 = 1000104001,
+    VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT                 = 1000104002,
+    VK_COLOR_SPACE_DCI_P3_LINEAR_EXT                        = 1000104003,
+    VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT                     = 1000104004,
+    VK_COLOR_SPACE_BT709_LINEAR_EXT                         = 1000104005,
+    VK_COLOR_SPACE_BT709_NONLINEAR_EXT                      = 1000104006,
+    VK_COLOR_SPACE_BT2020_LINEAR_EXT                        = 1000104007,
+    VK_COLOR_SPACE_HDR10_ST2084_EXT                         = 1000104008,
+    VK_COLOR_SPACE_DOLBYVISION_EXT                          = 1000104009,
+    VK_COLOR_SPACE_HDR10_HLG_EXT                            = 1000104010,
     VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT                      = 1000104011,
     VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT                   = 1000104012,
+    VK_COLOR_SPACE_PASS_THROUGH_EXT                         = 1000104013,
 }
 
 @extension("VK_EXT_debug_report") // 12
@@ -1245,6 +1246,9 @@
     VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT        = 30,
     VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT        = 31,
     VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,
+
+    //extension("VK_KHR_descriptor_update_template") // 86
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000,
 }
 
 @extension("VK_EXT_debug_report") // 12
@@ -3735,7 +3739,7 @@
 @extension("VK_KHX_device_group_creation") // 71
 class VkPhysicalDeviceGroupPropertiesKHX {
     VkStructureType                                 sType
-    const void*                                     pNext
+    void*                                           pNext
     u32                                             physicalDeviceCount
     VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE_KHX]  physicalDevices
     VkBool32                                        subsetAllocation
@@ -4223,7 +4227,7 @@
 @extension("VK_EXT_discard_rectangles") // 100
 class VkPhysicalDeviceDiscardRectanglePropertiesEXT {
     VkStructureType                             sType
-    const void*                                 pNext
+    void*                                       pNext
     u32                                         maxDiscardRectangles
 }
 
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 4b3b8bf..67eba86 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -43,7 +43,7 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 43
+#define VK_HEADER_VERSION 46
 
 
 #define VK_NULL_HANDLE 0
@@ -4011,6 +4011,30 @@
     const VkWriteDescriptorSet*                 pDescriptorWrites);
 #endif
 
+#define VK_KHR_incremental_present 1
+#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
+#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"
+
+typedef struct VkRectLayerKHR {
+    VkOffset2D    offset;
+    VkExtent2D    extent;
+    uint32_t      layer;
+} VkRectLayerKHR;
+
+typedef struct VkPresentRegionKHR {
+    uint32_t                 rectangleCount;
+    const VkRectLayerKHR*    pRectangles;
+} VkPresentRegionKHR;
+
+typedef struct VkPresentRegionsKHR {
+    VkStructureType              sType;
+    const void*                  pNext;
+    uint32_t                     swapchainCount;
+    const VkPresentRegionKHR*    pRegions;
+} VkPresentRegionsKHR;
+
+
+
 #define VK_KHR_descriptor_update_template 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplateKHR)
 
@@ -4086,7 +4110,7 @@
 #define VK_EXT_debug_report 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
 
-#define VK_EXT_DEBUG_REPORT_SPEC_VERSION  5
+#define VK_EXT_DEBUG_REPORT_SPEC_VERSION  6
 #define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
 #define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT
 
@@ -4125,6 +4149,7 @@
     VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30,
     VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31,
     VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000,
     VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
     VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT,
     VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1),
@@ -4781,7 +4806,7 @@
 
 typedef struct VkPhysicalDeviceGroupPropertiesKHX {
     VkStructureType     sType;
-    const void*         pNext;
+    void*               pNext;
     uint32_t            physicalDeviceCount;
     VkPhysicalDevice    physicalDevices[VK_MAX_DEVICE_GROUP_SIZE_KHX];
     VkBool32            subsetAllocation;
@@ -4906,7 +4931,7 @@
 
 
 
-#ifdef VK_USE_PLATFORM_WIN32_KHR
+#ifdef VK_USE_PLATFORM_WIN32_KHX
 #define VK_KHX_external_memory_win32 1
 #define VK_KHX_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
 #define VK_KHX_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHX_external_memory_win32"
@@ -4949,7 +4974,7 @@
     HANDLE                                      handle,
     VkMemoryWin32HandlePropertiesKHX*           pMemoryWin32HandleProperties);
 #endif
-#endif /* VK_USE_PLATFORM_WIN32_KHR */
+#endif /* VK_USE_PLATFORM_WIN32_KHX */
 
 #define VK_KHX_external_memory_fd 1
 #define VK_KHX_EXTERNAL_MEMORY_FD_SPEC_VERSION 1
@@ -5139,28 +5164,6 @@
     int*                                        pFd);
 #endif
 
-#define VK_KHR_incremental_present 1
-#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
-#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"
-
-typedef struct VkRectLayerKHR {
-    VkOffset2D offset;
-    VkExtent2D extent;
-    uint32_t layer;
-} VkRectLayerKHR;
-
-typedef struct VkPresentRegionKHR {
-    uint32_t rectangleCount;
-    const VkRectLayerKHR* pRectangles;
-} VkPresentRegionKHR;
-
-typedef struct VkPresentRegionsKHR {
-    VkStructureType sType;
-    const void* pNext;
-    uint32_t swapchainCount;
-    const VkPresentRegionKHR* pRegions;
-} VkPresentRegionsKHR;
-
 #define VK_NVX_device_generated_commands 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX)
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX)
@@ -5705,7 +5708,7 @@
 
 typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT {
     VkStructureType    sType;
-    const void*        pNext;
+    void*              pNext;
     uint32_t           maxDiscardRectangles;
 } VkPhysicalDeviceDiscardRectanglePropertiesEXT;
 
@@ -5730,9 +5733,10 @@
 #endif
 
 #define VK_EXT_swapchain_colorspace 1
-#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 1
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 2
 #define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
 
+
 #define VK_EXT_hdr_metadata 1
 #define VK_EXT_HDR_METADATA_SPEC_VERSION  1
 #define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata"
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 2fee8a5..3b785e6 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -981,25 +981,9 @@
     int gralloc_usage = 0;
     if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
         uint64_t consumer_usage, producer_usage;
-        if (GetData(device).driver_version == 256587285) {
-            // HACK workaround for loader/driver mismatch during transition to
-            // vkGetSwapchainGrallocUsage2ANDROID.
-            typedef VkResult(VKAPI_PTR *
-                             PFN_vkGetSwapchainGrallocUsage2ANDROID_HACK)(
-                VkDevice device, VkFormat format, VkImageUsageFlags imageUsage,
-                uint64_t * grallocConsumerUsage,
-                uint64_t * grallocProducerUsage);
-            auto get_swapchain_gralloc_usage =
-                reinterpret_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID_HACK>(
-                    dispatch.GetSwapchainGrallocUsage2ANDROID);
-            result = get_swapchain_gralloc_usage(
-                device, create_info->imageFormat, create_info->imageUsage,
-                &consumer_usage, &producer_usage);
-        } else {
-            result = dispatch.GetSwapchainGrallocUsage2ANDROID(
-                device, create_info->imageFormat, create_info->imageUsage,
-                swapchain_image_usage, &consumer_usage, &producer_usage);
-        }
+        result = dispatch.GetSwapchainGrallocUsage2ANDROID(
+            device, create_info->imageFormat, create_info->imageUsage,
+            swapchain_image_usage, &consumer_usage, &producer_usage);
         if (result != VK_SUCCESS) {
             ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
             return VK_ERROR_SURFACE_LOST_KHR;