Merge "libui: clean up GraphicBuffer interface" into oc-dev
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..03af56d
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+
+AccessModifierOffset: -4
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakBeforeMultilineStrings: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ConstructorInitializerIndentWidth: 6
+ContinuationIndentWidth: 8
+IndentWidth: 4
+PenaltyBreakBeforeFirstCallParameter: 100000
+SpacesBeforeTrailingComments: 1
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index cba8f36..5421a75 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -820,28 +820,33 @@
     if (timeout < 20000) {
         timeout = 20000;
     }
-    RunCommand("SYSTEM LOG", {"logcat", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+    RunCommand("SYSTEM LOG",
+               {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"},
                CommandOptions::WithTimeout(timeout / 1000).Build());
     timeout = logcat_timeout("events");
     if (timeout < 20000) {
         timeout = 20000;
     }
     RunCommand("EVENT LOG",
-               {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+               {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"},
                CommandOptions::WithTimeout(timeout / 1000).Build());
     timeout = logcat_timeout("radio");
     if (timeout < 20000) {
         timeout = 20000;
     }
     RunCommand("RADIO LOG",
-               {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-d", "*:v"},
+               {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"},
                CommandOptions::WithTimeout(timeout / 1000).Build());
 
     RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
 
     /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
     RunCommand("LAST LOGCAT",
-               {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-d", "*:v"});
+                {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-v", "uid",
+                        "-d", "*:v"});
 }
 
 static void DumpIpTables() {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 381e90c..c604ca0 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -289,6 +289,46 @@
     return 0;
 }
 
+/**
+ * Ensure that we have a hard-limit quota to protect against abusive apps;
+ * they should never use more than 90% of blocks or 50% of inodes.
+ */
+static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std::string& device,
+        uid_t uid) {
+    if (device.empty()) return 0;
+
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        PLOG(WARNING) << "Failed to find quota for " << uid;
+        return -1;
+    }
+
+    if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
+        auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
+        struct statvfs stat;
+        if (statvfs(path.c_str(), &stat) != 0) {
+            PLOG(WARNING) << "Failed to statvfs " << path;
+            return -1;
+        }
+
+        dq.dqb_valid = QIF_LIMITS;
+        dq.dqb_bhardlimit = (((stat.f_blocks * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
+        dq.dqb_ihardlimit = (stat.f_files / 2);
+        if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            PLOG(WARNING) << "Failed to set hard quota for " << uid;
+            return -1;
+        } else {
+            LOG(DEBUG) << "Applied hard quotas for " << uid;
+            return 0;
+        }
+    } else {
+        // Hard quota already set; assume it's reasonable
+        return 0;
+    }
+}
+
 binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
         const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
@@ -358,6 +398,10 @@
             return error("Failed to restorecon " + path);
         }
 
+        if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
+            return error("Failed to set hard quota " + path);
+        }
+
         if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
             const std::string profile_dir =
                     create_primary_current_profile_package_dir_path(userId, pkgname);
@@ -709,6 +753,14 @@
             }
         }
     }
+
+    // Data under /data/media doesn't have an app, but we still want
+    // to limit it to prevent abuse.
+    if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid),
+            multiuser_get_uid(userId, AID_MEDIA_RW))) {
+        return error("Failed to set hard quota for media_rw");
+    }
+
     return ok();
 }
 
@@ -2006,6 +2058,17 @@
                     reinterpret_cast<char*>(&dq)) == 0) {
                 LOG(DEBUG) << "Found " << source << " with quota";
                 mQuotaDevices[target] = source;
+
+                // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
+                // need to kick it again to enable DQUOT_LIMITS_ENABLED.
+                if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
+                        && errno != EBUSY) {
+                    PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
+                }
+                if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
+                        && errno != EBUSY) {
+                    PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
+                }
             }
         }
     }
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 360f71a..174ce77 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -99,7 +99,7 @@
 static int64_t free() {
     struct statvfs buf;
     if (!statvfs("/data/local/tmp", &buf)) {
-        return buf.f_bavail * buf.f_bsize;
+        return buf.f_bavail * buf.f_frsize;
     } else {
         PLOG(ERROR) << "Failed to statvfs";
         return -1;
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index fbe6edf..24c0b45 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -629,11 +629,10 @@
     return res;
 }
 
-int64_t data_disk_free(const std::string& data_path)
-{
+int64_t data_disk_free(const std::string& data_path) {
     struct statvfs sfs;
     if (statvfs(data_path.c_str(), &sfs) == 0) {
-        return sfs.f_bavail * sfs.f_bsize;
+        return sfs.f_bavail * sfs.f_frsize;
     } else {
         PLOG(ERROR) << "Couldn't statvfs " << data_path;
         return -1;
@@ -1030,6 +1029,10 @@
     } else if (st.st_gid == gid && actual_mode == target_mode) {
         // Everything looks good!
         return 0;
+    } else {
+        // Mismatched GID/mode is recoverable; fall through to update
+        LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid
+                << " but expected " << gid;
     }
 
     // Directory is owned correctly, but GID or mode mismatch means it's
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..45bb1d0 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;
@@ -374,7 +373,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 +394,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/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/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index 1f4387d..a680bc6 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -14,55 +14,52 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
-#define ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
+#pragma once
 
 #include <binder/IInterface.h>
-
-#include <ui/FrameStats.h>
+#include <binder/SafeInterface.h>
 #include <ui/PixelFormat.h>
 
 namespace android {
-// ----------------------------------------------------------------------------
 
+class FrameStats;
 class IGraphicBufferProducer;
 
-class ISurfaceComposerClient : public IInterface
-{
+class ISurfaceComposerClient : public IInterface {
 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,
-        eDestroyBackbuffer  = 0x00000020,
-        eSecure             = 0x00000080,
-        eNonPremultiplied   = 0x00000100,
-        eOpaque             = 0x00000400,
-        eProtectedByApp     = 0x00000800,
-        eProtectedByDRM     = 0x00001000,
-        eCursorWindow       = 0x00002000,
+        eHidden = 0x00000004,
+        eDestroyBackbuffer = 0x00000020,
+        eSecure = 0x00000080,
+        eNonPremultiplied = 0x00000100,
+        eOpaque = 0x00000400,
+        eProtectedByApp = 0x00000800,
+        eProtectedByDRM = 0x00001000,
+        eCursorWindow = 0x00002000,
 
-        eFXSurfaceNormal    = 0x00000000,
-        eFXSurfaceDim       = 0x00020000,
-        eFXSurfaceMask      = 0x000F0000,
+        eFXSurfaceNormal = 0x00000000,
+        eFXSurfaceDim = 0x00020000,
+        eFXSurfaceMask = 0x000F0000,
     };
 
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
      */
-    virtual status_t createSurface(
-            const String8& name, uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t flags,
-            const sp<IBinder>& parent, uint32_t windowType, uint32_t ownerUid,
-            sp<IBinder>* handle,
-            sp<IGraphicBufferProducer>* gbp) = 0;
+    virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
+                                   uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
+                                   uint32_t ownerUid, sp<IBinder>* handle,
+                                   sp<IGraphicBufferProducer>* gbp) = 0;
 
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
@@ -78,21 +75,14 @@
      * Requires ACCESS_SURFACE_FLINGER permission
      */
     virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
-
-    virtual status_t getTransformToDisplayInverse(const sp<IBinder>& handle,
-            bool* outTransformToDisplayInverse) const = 0;
 };
 
-// ----------------------------------------------------------------------------
-
-class BnSurfaceComposerClient: public BnInterface<ISurfaceComposerClient> {
+class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> {
 public:
-    virtual status_t onTransact(uint32_t code, const Parcel& data,
-            Parcel* reply, uint32_t flags = 0);
+    BnSurfaceComposerClient()
+          : SafeBnInterface<ISurfaceComposerClient>("BnSurfaceComposerClient") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
 };
 
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
+} // namespace android
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/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 1e8cf76..394425a 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -169,9 +169,6 @@
     status_t clearLayerFrameStats(const sp<IBinder>& token) const;
     status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
 
-    status_t getTransformToDisplayInverse(const sp<IBinder>& token,
-            bool* outTransformToDisplayInverse) const;
-
     static status_t clearAnimationFrameStats();
     static status_t getAnimationFrameStats(FrameStats* outStats);
 
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 8ee35bc..3cff7df 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -119,8 +119,6 @@
     status_t clearLayerFrameStats() const;
     status_t getLayerFrameStats(FrameStats* outStats) const;
 
-    status_t getTransformToDisplayInverse(bool* outTransformToDisplayInverse) const;
-
 private:
     // can't be copied
     SurfaceControl& operator = (SurfaceControl& rhs);
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 93b8684..b225128 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -71,6 +71,10 @@
         "libutils",
     ],
 
+    export_include_dirs: [
+        "include",
+    ],
+
     clang: true,
     sanitize: {
         misc_undefined: ["integer"],
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h
new file mode 100644
index 0000000..0e723c5
--- /dev/null
+++ b/libs/binder/include/binder/SafeInterface.h
@@ -0,0 +1,621 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <cutils/compiler.h>
+
+// Set to 1 to enable CallStacks when logging errors
+#define SI_DUMP_CALLSTACKS 0
+#if SI_DUMP_CALLSTACKS
+#include <utils/CallStack.h>
+#endif
+
+#include <functional>
+#include <type_traits>
+
+namespace android {
+namespace SafeInterface {
+
+// ParcelHandler is responsible for writing/reading various types to/from a Parcel in a generic way
+class ParcelHandler {
+public:
+    explicit ParcelHandler(const char* logTag) : mLogTag(logTag) {}
+
+    // Specializations for types with dedicated handling in Parcel
+    status_t read(const Parcel& parcel, bool* b) const {
+        return callParcel("readBool", [&]() { return parcel.readBool(b); });
+    }
+    status_t write(Parcel* parcel, bool b) const {
+        return callParcel("writeBool", [&]() { return parcel->writeBool(b); });
+    }
+    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); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type write(
+            Parcel* parcel, const T& t) const {
+        return callParcel("write(LightFlattenable)", [&]() { return parcel->write(t); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read(
+            const Parcel& parcel, T* t) const {
+        return callParcel("readParcelable", [&]() { return parcel.readParcelable(t); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type write(
+            Parcel* parcel, const T& t) const {
+        return callParcel("writeParcelable", [&]() { return parcel->writeParcelable(t); });
+    }
+    status_t read(const Parcel& parcel, String8* str) const {
+        return callParcel("readString8", [&]() { return parcel.readString8(str); });
+    }
+    status_t write(Parcel* parcel, const String8& str) const {
+        return callParcel("writeString8", [&]() { return parcel->writeString8(str); });
+    }
+    template <typename T>
+    status_t read(const Parcel& parcel, sp<T>* pointer) const {
+        return callParcel("readNullableStrongBinder",
+                          [&]() { return parcel.readNullableStrongBinder(pointer); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type write(
+            Parcel* parcel, const sp<T>& pointer) const {
+        return callParcel("writeStrongBinder",
+                          [&]() { return parcel->writeStrongBinder(pointer); });
+    }
+    template <typename T>
+    typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type write(
+            Parcel* parcel, const sp<T>& interface) const {
+        return write(parcel, IInterface::asBinder(interface));
+    }
+
+    // Templates to handle integral types. We use a struct template to require that the called
+    // function exactly matches the signedness and size of the argument (e.g., the argument isn't
+    // silently widened).
+    template <bool isSigned, size_t size, typename I>
+    struct HandleInt;
+    template <typename I>
+    struct HandleInt<true, 4, I> {
+        static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+            return handler.callParcel("readInt32", [&]() { return parcel.readInt32(i); });
+        }
+        static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+            return handler.callParcel("writeInt32", [&]() { return parcel->writeInt32(i); });
+        }
+    };
+    template <typename I>
+    struct HandleInt<false, 4, I> {
+        static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+            return handler.callParcel("readUint32", [&]() { return parcel.readUint32(i); });
+        }
+        static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+            return handler.callParcel("writeUint32", [&]() { return parcel->writeUint32(i); });
+        }
+    };
+    template <typename I>
+    typename std::enable_if<std::is_integral<I>::value, status_t>::type read(const Parcel& parcel,
+                                                                             I* i) const {
+        return HandleInt<std::is_signed<I>::value, sizeof(I), I>::read(*this, parcel, i);
+    }
+    template <typename I>
+    typename std::enable_if<std::is_integral<I>::value, status_t>::type write(Parcel* parcel,
+                                                                              I i) const {
+        return HandleInt<std::is_signed<I>::value, sizeof(I), I>::write(*this, parcel, i);
+    }
+
+private:
+    const char* const mLogTag;
+
+    // Helper to encapsulate error handling while calling the various Parcel methods
+    template <typename Function>
+    status_t callParcel(const char* name, Function f) const {
+        status_t error = f();
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            ALOG(LOG_ERROR, mLogTag, "Failed to %s, (%d: %s)", name, error, strerror(-error));
+#if SI_DUMP_CALLSTACKS
+            CallStack callStack(mLogTag);
+#endif
+        }
+        return error;
+    }
+};
+
+// Utility struct template which allows us to retrieve the types of the parameters of a member
+// function pointer
+template <typename T>
+struct ParamExtractor;
+template <typename Class, typename Return, typename... Params>
+struct ParamExtractor<Return (Class::*)(Params...)> {
+    using ParamTuple = std::tuple<Params...>;
+};
+template <typename Class, typename Return, typename... Params>
+struct ParamExtractor<Return (Class::*)(Params...) const> {
+    using ParamTuple = std::tuple<Params...>;
+};
+
+} // namespace SafeInterface
+
+template <typename Interface>
+class SafeBpInterface : public BpInterface<Interface> {
+protected:
+    SafeBpInterface(const sp<IBinder>& impl, const char* logTag)
+          : BpInterface<Interface>(impl), mLogTag(logTag) {}
+    ~SafeBpInterface() override = default;
+
+    // callRemote is used to invoke a synchronous procedure call over Binder
+    template <typename Method, typename TagType, typename... Args>
+    status_t callRemote(TagType tag, Args&&... args) const {
+        static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t");
+
+        // Verify that the arguments are compatible with the parameters
+        using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+        static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value,
+                      "Invalid argument type");
+
+        // Write the input arguments to the data Parcel
+        Parcel data;
+        data.writeInterfaceToken(this->getInterfaceDescriptor());
+
+        status_t error = writeInputs(&data, std::forward<Args>(args)...);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by writeInputs
+            return error;
+        }
+
+        // Send the data Parcel to the remote and retrieve the reply parcel
+        Parcel reply;
+        error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error);
+#if SI_DUMP_CALLSTACKS
+            CallStack callStack(mLogTag);
+#endif
+            return error;
+        }
+
+        // Read the outputs from the reply Parcel into the output arguments
+        error = readOutputs(reply, std::forward<Args>(args)...);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by readOutputs
+            return error;
+        }
+
+        // Retrieve the result code from the reply Parcel
+        status_t result = NO_ERROR;
+        error = reply.readInt32(&result);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            ALOG(LOG_ERROR, mLogTag, "Failed to obtain result");
+#if SI_DUMP_CALLSTACKS
+            CallStack callStack(mLogTag);
+#endif
+            return error;
+        }
+        return result;
+    }
+
+    // callRemoteAsync is used to invoke an asynchronous procedure call over Binder
+    template <typename Method, typename TagType, typename... Args>
+    void callRemoteAsync(TagType tag, Args&&... args) const {
+        static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t");
+
+        // Verify that the arguments are compatible with the parameters
+        using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+        static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value,
+                      "Invalid argument type");
+
+        // Write the input arguments to the data Parcel
+        Parcel data;
+        data.writeInterfaceToken(this->getInterfaceDescriptor());
+        status_t error = writeInputs(&data, std::forward<Args>(args)...);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by writeInputs
+            return;
+        }
+
+        // There will be no data in the reply Parcel since the call is one-way
+        Parcel reply;
+        error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply,
+                                         IBinder::FLAG_ONEWAY);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error);
+#if SI_DUMP_CALLSTACKS
+            CallStack callStack(mLogTag);
+#endif
+        }
+    }
+
+private:
+    const char* const mLogTag;
+
+    // This struct provides information on whether the decayed types of the elements at Index in the
+    // tuple types T and U (that is, the types after stripping cv-qualifiers, removing references,
+    // and a few other less common operations) are the same
+    template <size_t Index, typename T, typename U>
+    struct DecayedElementsMatch {
+    private:
+        using FirstT = typename std::tuple_element<Index, T>::type;
+        using DecayedT = typename std::decay<FirstT>::type;
+        using FirstU = typename std::tuple_element<Index, U>::type;
+        using DecayedU = typename std::decay<FirstU>::type;
+
+    public:
+        static constexpr bool value = std::is_same<DecayedT, DecayedU>::value;
+    };
+
+    // When comparing whether the argument types match the parameter types, we first decay them (see
+    // DecayedElementsMatch) to avoid falsely flagging, say, T&& against T even though they are
+    // equivalent enough for our purposes
+    template <typename T, typename U>
+    struct ArgsMatchParams {};
+    template <typename... Args, typename... Params>
+    struct ArgsMatchParams<std::tuple<Args...>, std::tuple<Params...>> {
+        static_assert(sizeof...(Args) <= sizeof...(Params), "Too many arguments");
+        static_assert(sizeof...(Args) >= sizeof...(Params), "Not enough arguments");
+
+    private:
+        template <size_t Index>
+        static constexpr typename std::enable_if<(Index < sizeof...(Args)), bool>::type
+        elementsMatch() {
+            if (!DecayedElementsMatch<Index, std::tuple<Args...>, std::tuple<Params...>>::value) {
+                return false;
+            }
+            return elementsMatch<Index + 1>();
+        }
+        template <size_t Index>
+        static constexpr typename std::enable_if<(Index >= sizeof...(Args)), bool>::type
+        elementsMatch() {
+            return true;
+        }
+
+    public:
+        static constexpr bool value = elementsMatch<0>();
+    };
+
+    // Since we assume that pointer arguments are outputs, we can use this template struct to
+    // determine whether or not a given argument is fundamentally a pointer type and thus an output
+    template <typename T>
+    struct IsPointerIfDecayed {
+    private:
+        using Decayed = typename std::decay<T>::type;
+
+    public:
+        static constexpr bool value = std::is_pointer<Decayed>::value;
+    };
+
+    template <typename T>
+    typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type writeIfInput(
+            Parcel* data, T&& t) const {
+        return SafeInterface::ParcelHandler{mLogTag}.write(data, std::forward<T>(t));
+    }
+    template <typename T>
+    typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type writeIfInput(
+            Parcel* /*data*/, T&& /*t*/) const {
+        return NO_ERROR;
+    }
+
+    // This method iterates through all of the arguments, writing them to the data Parcel if they
+    // are an input (i.e., if they are not a pointer type)
+    template <typename T, typename... Remaining>
+    status_t writeInputs(Parcel* data, T&& t, Remaining&&... remaining) const {
+        status_t error = writeIfInput(data, std::forward<T>(t));
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by writeIfInput
+            return error;
+        }
+        return writeInputs(data, std::forward<Remaining>(remaining)...);
+    }
+    static status_t writeInputs(Parcel* /*data*/) { return NO_ERROR; }
+
+    template <typename T>
+    typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type readIfOutput(
+            const Parcel& reply, T&& t) const {
+        return SafeInterface::ParcelHandler{mLogTag}.read(reply, std::forward<T>(t));
+    }
+    template <typename T>
+    static typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type readIfOutput(
+            const Parcel& /*reply*/, T&& /*t*/) {
+        return NO_ERROR;
+    }
+
+    // Similar to writeInputs except that it reads output arguments from the reply Parcel
+    template <typename T, typename... Remaining>
+    status_t readOutputs(const Parcel& reply, T&& t, Remaining&&... remaining) const {
+        status_t error = readIfOutput(reply, std::forward<T>(t));
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by readIfOutput
+            return error;
+        }
+        return readOutputs(reply, std::forward<Remaining>(remaining)...);
+    }
+    static status_t readOutputs(const Parcel& /*data*/) { return NO_ERROR; }
+};
+
+template <typename Interface>
+class SafeBnInterface : public BnInterface<Interface> {
+public:
+    explicit SafeBnInterface(const char* logTag) : mLogTag(logTag) {}
+
+protected:
+    template <typename Method>
+    status_t callLocal(const Parcel& data, Parcel* reply, Method method) {
+        CHECK_INTERFACE(this, data, reply);
+
+        // Since we need to both pass inputs into the call as well as retrieve outputs, we create a
+        // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the
+        // outputs. When we ultimately call into the method, we will pass the addresses of the
+        // output arguments instead of their tuple members directly, but the storage will live in
+        // the tuple.
+        using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+        typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{};
+
+        // Read the inputs from the data Parcel into the argument tuple
+        status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by read
+            return error;
+        }
+
+        // Call the local method
+        status_t result = MethodCaller<ParamTuple>::call(this, method, &rawArgs);
+
+        // Extract the outputs from the argument tuple and write them into the reply Parcel
+        error = OutputWriter<ParamTuple>{mLogTag}.writeOutputs(reply, &rawArgs);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by write
+            return error;
+        }
+
+        // Return the result code in the reply Parcel
+        error = reply->writeInt32(result);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            ALOG(LOG_ERROR, mLogTag, "Failed to write result");
+#if SI_DUMP_CALLSTACKS
+            CallStack callStack(mLogTag);
+#endif
+            return error;
+        }
+        return NO_ERROR;
+    }
+
+    template <typename Method>
+    status_t callLocalAsync(const Parcel& data, Parcel* /*reply*/, Method method) {
+        // reply is not actually used by CHECK_INTERFACE
+        CHECK_INTERFACE(this, data, reply);
+
+        // Since we need to both pass inputs into the call as well as retrieve outputs, we create a
+        // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the
+        // outputs. When we ultimately call into the method, we will pass the addresses of the
+        // output arguments instead of their tuple members directly, but the storage will live in
+        // the tuple.
+        using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+        typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{};
+
+        // Read the inputs from the data Parcel into the argument tuple
+        status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs);
+        if (CC_UNLIKELY(error != NO_ERROR)) {
+            // A message will have been logged by read
+            return error;
+        }
+
+        // Call the local method
+        MethodCaller<ParamTuple>::callVoid(this, method, &rawArgs);
+
+        // After calling, there is nothing more to do since asynchronous calls do not return a value
+        // to the caller
+        return NO_ERROR;
+    }
+
+private:
+    const char* const mLogTag;
+
+    // RemoveFirst strips the first element from a tuple.
+    // For example, given T = std::tuple<A, B, C>, RemoveFirst<T>::type = std::tuple<B, C>
+    template <typename T, typename... Args>
+    struct RemoveFirst;
+    template <typename T, typename... Args>
+    struct RemoveFirst<std::tuple<T, Args...>> {
+        using type = std::tuple<Args...>;
+    };
+
+    // RawConverter strips a tuple down to its fundamental types, discarding both pointers and
+    // references. This allows us to allocate storage for both input (non-pointer) arguments and
+    // output (pointer) arguments in one tuple.
+    // For example, given T = std::tuple<const A&, B*>, RawConverter<T>::type = std::tuple<A, B>
+    template <typename Unconverted, typename... Converted>
+    struct RawConverter;
+    template <typename Unconverted, typename... Converted>
+    struct RawConverter<std::tuple<Converted...>, Unconverted> {
+    private:
+        using ElementType = typename std::tuple_element<0, Unconverted>::type;
+        using Decayed = typename std::decay<ElementType>::type;
+        using WithoutPointer = typename std::remove_pointer<Decayed>::type;
+
+    public:
+        using type = typename RawConverter<std::tuple<Converted..., WithoutPointer>,
+                                           typename RemoveFirst<Unconverted>::type>::type;
+    };
+    template <typename... Converted>
+    struct RawConverter<std::tuple<Converted...>, std::tuple<>> {
+        using type = std::tuple<Converted...>;
+    };
+
+    // This provides a simple way to determine whether the indexed element of Args... is a pointer
+    template <size_t I, typename... Args>
+    struct ElementIsPointer {
+    private:
+        using ElementType = typename std::tuple_element<I, std::tuple<Args...>>::type;
+
+    public:
+        static constexpr bool value = std::is_pointer<ElementType>::value;
+    };
+
+    // This class iterates over the parameter types, and if a given parameter is an input
+    // (i.e., is not a pointer), reads the corresponding argument tuple element from the data Parcel
+    template <typename... Params>
+    class InputReader;
+    template <typename... Params>
+    class InputReader<std::tuple<Params...>> {
+    public:
+        explicit InputReader(const char* logTag) : mLogTag(logTag) {}
+
+        // Note that in this case (as opposed to in SafeBpInterface), we iterate using an explicit
+        // index (starting with 0 here) instead of using recursion and stripping the first element.
+        // This is because in SafeBpInterface we aren't actually operating on a real tuple, but are
+        // instead just using a tuple as a convenient container for variadic types, whereas here we
+        // can't modify the argument tuple without causing unnecessary copies or moves of the data
+        // contained therein.
+        template <typename RawTuple>
+        status_t readInputs(const Parcel& data, RawTuple* args) {
+            return dispatchArg<0>(data, args);
+        }
+
+    private:
+        const char* const mLogTag;
+
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type readIfInput(
+                const Parcel& data, RawTuple* args) {
+            return SafeInterface::ParcelHandler{mLogTag}.read(data, &std::get<I>(*args));
+        }
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type readIfInput(
+                const Parcel& /*data*/, RawTuple* /*args*/) {
+            return NO_ERROR;
+        }
+
+        // Recursively iterate through the arguments
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg(
+                const Parcel& data, RawTuple* args) {
+            status_t error = readIfInput<I>(data, args);
+            if (CC_UNLIKELY(error != NO_ERROR)) {
+                // A message will have been logged in read
+                return error;
+            }
+            return dispatchArg<I + 1>(data, args);
+        }
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg(
+                const Parcel& /*data*/, RawTuple* /*args*/) {
+            return NO_ERROR;
+        }
+    };
+
+    // getForCall uses the types of the parameters to determine whether a given element of the
+    // argument tuple is an input, which should be passed directly into the call, or an output, for
+    // which its address should be passed into the call
+    template <size_t I, typename RawTuple, typename... Params>
+    static typename std::enable_if<
+            ElementIsPointer<I, Params...>::value,
+            typename std::tuple_element<I, std::tuple<Params...>>::type>::type
+    getForCall(RawTuple* args) {
+        return &std::get<I>(*args);
+    }
+    template <size_t I, typename RawTuple, typename... Params>
+    static typename std::enable_if<
+            !ElementIsPointer<I, Params...>::value,
+            typename std::tuple_element<I, std::tuple<Params...>>::type>::type&
+    getForCall(RawTuple* args) {
+        return std::get<I>(*args);
+    }
+
+    // This template class uses std::index_sequence and parameter pack expansion to call the given
+    // method using the elements of the argument tuple (after those arguments are passed through
+    // getForCall to get addresses instead of values for output arguments)
+    template <typename... Params>
+    struct MethodCaller;
+    template <typename... Params>
+    struct MethodCaller<std::tuple<Params...>> {
+    public:
+        // The calls through these to the helper methods are necessary to generate the
+        // std::index_sequences used to unpack the argument tuple into the method call
+        template <typename Class, typename MemberFunction, typename RawTuple>
+        static status_t call(Class* instance, MemberFunction function, RawTuple* args) {
+            return callHelper(instance, function, args, std::index_sequence_for<Params...>{});
+        }
+        template <typename Class, typename MemberFunction, typename RawTuple>
+        static void callVoid(Class* instance, MemberFunction function, RawTuple* args) {
+            callVoidHelper(instance, function, args, std::index_sequence_for<Params...>{});
+        }
+
+    private:
+        template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I>
+        static status_t callHelper(Class* instance, MemberFunction function, RawTuple* args,
+                                   std::index_sequence<I...> /*unused*/) {
+            return (instance->*function)(getForCall<I, RawTuple, Params...>(args)...);
+        }
+        template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I>
+        static void callVoidHelper(Class* instance, MemberFunction function, RawTuple* args,
+                                   std::index_sequence<I...> /*unused*/) {
+            (instance->*function)(getForCall<I, RawTuple, Params...>(args)...);
+        }
+    };
+
+    // This class iterates over the parameter types, and if a given parameter is an output
+    // (i.e., is a pointer), writes the corresponding argument tuple element into the reply Parcel
+    template <typename... Params>
+    struct OutputWriter;
+    template <typename... Params>
+    struct OutputWriter<std::tuple<Params...>> {
+    public:
+        explicit OutputWriter(const char* logTag) : mLogTag(logTag) {}
+
+        // See the note on InputReader::readInputs for why this differs from the arguably simpler
+        // RemoveFirst approach in SafeBpInterface
+        template <typename RawTuple>
+        status_t writeOutputs(Parcel* reply, RawTuple* args) {
+            return dispatchArg<0>(reply, args);
+        }
+
+    private:
+        const char* const mLogTag;
+
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type
+        writeIfOutput(Parcel* reply, RawTuple* args) {
+            return SafeInterface::ParcelHandler{mLogTag}.write(reply, std::get<I>(*args));
+        }
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type
+        writeIfOutput(Parcel* /*reply*/, RawTuple* /*args*/) {
+            return NO_ERROR;
+        }
+
+        // Recursively iterate through the arguments
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg(
+                Parcel* reply, RawTuple* args) {
+            status_t error = writeIfOutput<I>(reply, args);
+            if (CC_UNLIKELY(error != NO_ERROR)) {
+                // A message will have been logged in read
+                return error;
+            }
+            return dispatchArg<I + 1>(reply, args);
+        }
+        template <std::size_t I, typename RawTuple>
+        typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg(
+                Parcel* /*reply*/, RawTuple* /*args*/) {
+            return NO_ERROR;
+        }
+    };
+};
+
+} // namespace android
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 327ecad..1ee4b6f 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -80,3 +80,27 @@
         "libbase",
     ],
 }
+
+cc_test {
+    name: "binderSafeInterfaceTest",
+    srcs: ["binderSafeInterfaceTest.cpp"],
+
+    cppflags: [
+        "-Werror",
+        "-Weverything",
+        "-Wno-c++98-compat",
+        "-Wno-c++98-compat-pedantic",
+        "-Wno-global-constructors",
+        "-Wno-padded",
+        "-Wno-weak-vtables",
+    ],
+
+    cpp_std: "experimental",
+    gnu_extensions: false,
+
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
new file mode 100644
index 0000000..ac2f4d5
--- /dev/null
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -0,0 +1,514 @@
+/*
+ * Copyright 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.
+ */
+
+#include <binder/SafeInterface.h>
+
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/ProcessState.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#include <gtest/gtest.h>
+#pragma clang diagnostic pop
+
+#include <optional>
+
+using namespace std::chrono_literals; // NOLINT - google-build-using-namespace
+
+namespace android {
+namespace tests {
+
+// This class serves two purposes:
+//   1) It ensures that the implementation doesn't require copying or moving the data (for
+//      efficiency purposes)
+//   2) It tests that Parcelables can be passed correctly
+class NoCopyNoMove : public Parcelable {
+public:
+    NoCopyNoMove() = default;
+    explicit NoCopyNoMove(int32_t value) : mValue(value) {}
+    ~NoCopyNoMove() override = default;
+
+    // Not copyable
+    NoCopyNoMove(const NoCopyNoMove&) = delete;
+    NoCopyNoMove& operator=(const NoCopyNoMove&) = delete;
+
+    // Not movable
+    NoCopyNoMove(NoCopyNoMove&&) = delete;
+    NoCopyNoMove& operator=(NoCopyNoMove&&) = delete;
+
+    // Parcelable interface
+    status_t writeToParcel(Parcel* parcel) const override { return parcel->writeInt32(mValue); }
+    status_t readFromParcel(const Parcel* parcel) override { return parcel->readInt32(&mValue); }
+
+    int32_t getValue() const { return mValue; }
+    void setValue(int32_t value) { mValue = value; }
+
+private:
+    int32_t mValue = 0;
+    uint8_t mPadding[4] = {}; // Avoids a warning from -Wpadded
+};
+
+struct TestLightFlattenable : LightFlattenablePod<TestLightFlattenable> {
+    TestLightFlattenable() = default;
+    explicit TestLightFlattenable(int32_t v) : value(v) {}
+    int32_t value = 0;
+};
+
+class ExitOnDeath : public IBinder::DeathRecipient {
+public:
+    ~ExitOnDeath() override = default;
+
+    void binderDied(const wp<IBinder>& /*who*/) override {
+        ALOG(LOG_INFO, "ExitOnDeath", "Exiting");
+        exit(0);
+    }
+};
+
+// This callback class is used to test both one-way transactions and that sp<IInterface> can be
+// passed correctly
+class ICallback : public IInterface {
+public:
+    DECLARE_META_INTERFACE(Callback)
+
+    enum class Tag : uint32_t {
+        OnCallback = IBinder::FIRST_CALL_TRANSACTION,
+        Last,
+    };
+
+    virtual void onCallback(int32_t aPlusOne) = 0;
+};
+
+class BpCallback : public SafeBpInterface<ICallback> {
+public:
+    explicit BpCallback(const sp<IBinder>& impl) : SafeBpInterface<ICallback>(impl, getLogTag()) {}
+
+    void onCallback(int32_t aPlusOne) override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemoteAsync<decltype(&ICallback::onCallback)>(Tag::OnCallback, aPlusOne);
+    }
+
+private:
+    static constexpr const char* getLogTag() { return "BpCallback"; }
+};
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+IMPLEMENT_META_INTERFACE(Callback, "android.gfx.tests.ICallback");
+#pragma clang diagnostic pop
+
+class BnCallback : public SafeBnInterface<ICallback> {
+public:
+    BnCallback() : SafeBnInterface("BnCallback") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t /*flags*/) override {
+        EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+        EXPECT_LT(code, static_cast<uint32_t>(ICallback::Tag::Last));
+        ICallback::Tag tag = static_cast<ICallback::Tag>(code);
+        switch (tag) {
+            case ICallback::Tag::OnCallback: {
+                return callLocalAsync(data, reply, &ICallback::onCallback);
+            }
+            case ICallback::Tag::Last:
+                // Should not be possible because of the asserts at the beginning of the method
+                [&]() { FAIL(); }();
+                return UNKNOWN_ERROR;
+        }
+    }
+};
+
+class ISafeInterfaceTest : public IInterface {
+public:
+    DECLARE_META_INTERFACE(SafeInterfaceTest)
+
+    enum class Tag : uint32_t {
+        SetDeathToken = IBinder::FIRST_CALL_TRANSACTION,
+        ReturnsNoMemory,
+        LogicalNot,
+        IncrementLightFlattenable,
+        IncrementNoCopyNoMove,
+        ToUpper,
+        CallMeBack,
+        IncrementInt32,
+        IncrementUint32,
+        IncrementTwo,
+        Last,
+    };
+
+    // This is primarily so that the remote service dies when the test does, but it also serves to
+    // test the handling of sp<IBinder> and non-const methods
+    virtual status_t setDeathToken(const sp<IBinder>& token) = 0;
+
+    // This is the most basic test since it doesn't require parceling any arguments
+    virtual status_t returnsNoMemory() const = 0;
+
+    // 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 TestLightFlattenable& a,
+                               TestLightFlattenable* aPlusOne) const = 0;
+    virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0;
+    virtual status_t toUpper(const String8& str, String8* upperStr) const = 0;
+    // As mentioned above, sp<IBinder> is already tested by setDeathToken
+    virtual void callMeBack(const sp<ICallback>& callback, int32_t a) const = 0;
+    virtual status_t increment(int32_t a, int32_t* aPlusOne) const = 0;
+    virtual status_t increment(uint32_t a, uint32_t* aPlusOne) const = 0;
+
+    // This tests that input/output parameter interleaving works correctly
+    virtual status_t increment(int32_t a, int32_t* aPlusOne, int32_t b,
+                               int32_t* bPlusOne) const = 0;
+};
+
+class BpSafeInterfaceTest : public SafeBpInterface<ISafeInterfaceTest> {
+public:
+    explicit BpSafeInterfaceTest(const sp<IBinder>& impl)
+          : SafeBpInterface<ISafeInterfaceTest>(impl, getLogTag()) {}
+
+    status_t setDeathToken(const sp<IBinder>& token) override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<decltype(&ISafeInterfaceTest::setDeathToken)>(Tag::SetDeathToken, token);
+    }
+    status_t returnsNoMemory() const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<decltype(&ISafeInterfaceTest::returnsNoMemory)>(Tag::ReturnsNoMemory);
+    }
+    status_t logicalNot(bool a, bool* notA) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<decltype(&ISafeInterfaceTest::logicalNot)>(Tag::LogicalNot, a, notA);
+    }
+    status_t increment(const TestLightFlattenable& a,
+                       TestLightFlattenable* aPlusOne) const override {
+        using Signature = status_t (ISafeInterfaceTest::*)(const TestLightFlattenable&,
+                                                           TestLightFlattenable*) const;
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<Signature>(Tag::IncrementLightFlattenable, a, aPlusOne);
+    }
+    status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
+                                                           NoCopyNoMove* aPlusOne) const;
+        return callRemote<Signature>(Tag::IncrementNoCopyNoMove, a, aPlusOne);
+    }
+    status_t toUpper(const String8& str, String8* upperStr) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemote<decltype(&ISafeInterfaceTest::toUpper)>(Tag::ToUpper, str, upperStr);
+    }
+    void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return callRemoteAsync<decltype(&ISafeInterfaceTest::callMeBack)>(Tag::CallMeBack, callback,
+                                                                          a);
+    }
+    status_t increment(int32_t a, int32_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const;
+        return callRemote<Signature>(Tag::IncrementInt32, a, aPlusOne);
+    }
+    status_t increment(uint32_t a, uint32_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
+        return callRemote<Signature>(Tag::IncrementUint32, a, aPlusOne);
+    }
+    status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature =
+                status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t, int32_t*) const;
+        return callRemote<Signature>(Tag::IncrementTwo, a, aPlusOne, b, bPlusOne);
+    }
+
+private:
+    static constexpr const char* getLogTag() { return "BpSafeInterfaceTest"; }
+};
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+IMPLEMENT_META_INTERFACE(SafeInterfaceTest, "android.gfx.tests.ISafeInterfaceTest");
+
+static sp<IBinder::DeathRecipient> getDeathRecipient() {
+    static sp<IBinder::DeathRecipient> recipient = new ExitOnDeath;
+    return recipient;
+}
+#pragma clang diagnostic pop
+
+class BnSafeInterfaceTest : public SafeBnInterface<ISafeInterfaceTest> {
+public:
+    BnSafeInterfaceTest() : SafeBnInterface(getLogTag()) {}
+
+    status_t setDeathToken(const sp<IBinder>& token) override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        token->linkToDeath(getDeathRecipient());
+        return NO_ERROR;
+    }
+    status_t returnsNoMemory() const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        return NO_MEMORY;
+    }
+    status_t logicalNot(bool a, bool* notA) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *notA = !a;
+        return NO_ERROR;
+    }
+    status_t increment(const TestLightFlattenable& a,
+                       TestLightFlattenable* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        aPlusOne->value = a.value + 1;
+        return NO_ERROR;
+    }
+    status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        aPlusOne->setValue(a.getValue() + 1);
+        return NO_ERROR;
+    }
+    status_t toUpper(const String8& str, String8* upperStr) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *upperStr = str;
+        upperStr->toUpper();
+        return NO_ERROR;
+    }
+    void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        callback->onCallback(a + 1);
+    }
+    status_t increment(int32_t a, int32_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = a + 1;
+        return NO_ERROR;
+    }
+    status_t increment(uint32_t a, uint32_t* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = a + 1;
+        return NO_ERROR;
+    }
+    status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = a + 1;
+        *bPlusOne = b + 1;
+        return NO_ERROR;
+    }
+
+    // BnInterface
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t /*flags*/) override {
+        EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+        EXPECT_LT(code, static_cast<uint32_t>(Tag::Last));
+        ISafeInterfaceTest::Tag tag = static_cast<ISafeInterfaceTest::Tag>(code);
+        switch (tag) {
+            case ISafeInterfaceTest::Tag::SetDeathToken: {
+                return callLocal(data, reply, &ISafeInterfaceTest::setDeathToken);
+            }
+            case ISafeInterfaceTest::Tag::ReturnsNoMemory: {
+                return callLocal(data, reply, &ISafeInterfaceTest::returnsNoMemory);
+            }
+            case ISafeInterfaceTest::Tag::LogicalNot: {
+                return callLocal(data, reply, &ISafeInterfaceTest::logicalNot);
+            }
+            case ISafeInterfaceTest::Tag::IncrementLightFlattenable: {
+                using Signature =
+                        status_t (ISafeInterfaceTest::*)(const TestLightFlattenable& a,
+                                                         TestLightFlattenable* aPlusOne) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementNoCopyNoMove: {
+                using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
+                                                                   NoCopyNoMove* aPlusOne) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::ToUpper: {
+                return callLocal(data, reply, &ISafeInterfaceTest::toUpper);
+            }
+            case ISafeInterfaceTest::Tag::CallMeBack: {
+                return callLocalAsync(data, reply, &ISafeInterfaceTest::callMeBack);
+            }
+            case ISafeInterfaceTest::Tag::IncrementInt32: {
+                using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementUint32: {
+                using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::IncrementTwo: {
+                using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t,
+                                                                   int32_t*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
+            case ISafeInterfaceTest::Tag::Last:
+                // Should not be possible because of the asserts at the beginning of the method
+                [&]() { FAIL(); }();
+                return UNKNOWN_ERROR;
+        }
+    }
+
+private:
+    static constexpr const char* getLogTag() { return "BnSafeInterfaceTest"; }
+};
+
+class SafeInterfaceTest : public ::testing::Test {
+public:
+    SafeInterfaceTest() : mSafeInterfaceTest(getRemoteService()) {
+        ProcessState::self()->startThreadPool();
+    }
+    ~SafeInterfaceTest() override = default;
+
+protected:
+    sp<ISafeInterfaceTest> mSafeInterfaceTest;
+
+private:
+    static constexpr const char* getLogTag() { return "SafeInterfaceTest"; }
+
+    sp<ISafeInterfaceTest> getRemoteService() {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+        static std::mutex sMutex;
+        static sp<ISafeInterfaceTest> sService;
+        static sp<IBinder> sDeathToken = new BBinder;
+#pragma clang diagnostic pop
+
+        std::unique_lock<decltype(sMutex)> lock;
+        if (sService == nullptr) {
+            ALOG(LOG_INFO, getLogTag(), "Forking remote process");
+            pid_t forkPid = fork();
+            EXPECT_NE(forkPid, -1);
+
+            const String16 serviceName("SafeInterfaceTest");
+
+            if (forkPid == 0) {
+                ALOG(LOG_INFO, getLogTag(), "Remote process checking in");
+                sp<ISafeInterfaceTest> nativeService = new BnSafeInterfaceTest;
+                defaultServiceManager()->addService(serviceName,
+                                                    IInterface::asBinder(nativeService));
+                ProcessState::self()->startThreadPool();
+                IPCThreadState::self()->joinThreadPool();
+                // We shouldn't get to this point
+                [&]() { FAIL(); }();
+            }
+
+            sp<IBinder> binder = defaultServiceManager()->getService(serviceName);
+            sService = interface_cast<ISafeInterfaceTest>(binder);
+            EXPECT_TRUE(sService != nullptr);
+
+            sService->setDeathToken(sDeathToken);
+        }
+
+        return sService;
+    }
+};
+
+TEST_F(SafeInterfaceTest, TestReturnsNoMemory) {
+    status_t result = mSafeInterfaceTest->returnsNoMemory();
+    ASSERT_EQ(NO_MEMORY, result);
+}
+
+TEST_F(SafeInterfaceTest, TestLogicalNot) {
+    const bool a = true;
+    bool notA = true;
+    status_t result = mSafeInterfaceTest->logicalNot(a, &notA);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(!a, notA);
+    // Test both since we don't want to accidentally catch a default false somewhere
+    const bool b = false;
+    bool notB = false;
+    result = mSafeInterfaceTest->logicalNot(b, &notB);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(!b, notB);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementLightFlattenable) {
+    const TestLightFlattenable a{1};
+    TestLightFlattenable aPlusOne{0};
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a.value + 1, aPlusOne.value);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementNoCopyNoMove) {
+    const NoCopyNoMove a{1};
+    NoCopyNoMove aPlusOne{0};
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a.getValue() + 1, aPlusOne.getValue());
+}
+
+TEST_F(SafeInterfaceTest, TestToUpper) {
+    const String8 str{"Hello, world!"};
+    String8 upperStr;
+    status_t result = mSafeInterfaceTest->toUpper(str, &upperStr);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_TRUE(upperStr == String8{"HELLO, WORLD!"});
+}
+
+TEST_F(SafeInterfaceTest, TestCallMeBack) {
+    class CallbackReceiver : public BnCallback {
+    public:
+        void onCallback(int32_t aPlusOne) override {
+            ALOG(LOG_INFO, "CallbackReceiver", "%s", __PRETTY_FUNCTION__);
+            std::unique_lock<decltype(mMutex)> lock(mMutex);
+            mValue = aPlusOne;
+            mCondition.notify_one();
+        }
+
+        std::optional<int32_t> waitForCallback() {
+            std::unique_lock<decltype(mMutex)> lock(mMutex);
+            bool success =
+                    mCondition.wait_for(lock, 100ms, [&]() { return static_cast<bool>(mValue); });
+            return success ? mValue : std::nullopt;
+        }
+
+    private:
+        std::mutex mMutex;
+        std::condition_variable mCondition;
+        std::optional<int32_t> mValue;
+    };
+
+    sp<CallbackReceiver> receiver = new CallbackReceiver;
+    const int32_t a = 1;
+    mSafeInterfaceTest->callMeBack(receiver, a);
+    auto result = receiver->waitForCallback();
+    ASSERT_TRUE(result);
+    ASSERT_EQ(a + 1, *result);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementInt32) {
+    const int32_t a = 1;
+    int32_t aPlusOne = 0;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementUint32) {
+    const uint32_t a = 1;
+    uint32_t aPlusOne = 0;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementTwo) {
+    const int32_t a = 1;
+    int32_t aPlusOne = 0;
+    const int32_t b = 2;
+    int32_t bPlusOne = 0;
+    status_t result = mSafeInterfaceTest->increment(1, &aPlusOne, 2, &bPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a + 1, aPlusOne);
+    ASSERT_EQ(b + 1, bPlusOne);
+}
+
+} // namespace tests
+} // namespace android
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 8acdfed..d4e4dc3 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -287,6 +287,9 @@
     }
 
     if (item->mGraphicBuffer != NULL) {
+        if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
+            freeBufferLocked(item->mSlot);
+        }
         mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
     }
 
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index db8a517..2d2146b 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -17,116 +17,56 @@
 // tag as surfaceflinger
 #define LOG_TAG "SurfaceFlinger"
 
-#include <stdio.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <sys/types.h>
 
-#include <binder/Parcel.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <binder/Parcel.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>
-#include <private/gui/LayerState.h>
-
-// ---------------------------------------------------------------------------
 
 namespace android {
 
-enum {
-    CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
-    DESTROY_SURFACE,
-    CLEAR_LAYER_FRAME_STATS,
-    GET_LAYER_FRAME_STATS,
-    GET_TRANSFORM_TO_DISPLAY_INVERSE
-};
-
-class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
-{
+class BpSurfaceComposerClient : public SafeBpInterface<ISurfaceComposerClient> {
 public:
     explicit BpSurfaceComposerClient(const sp<IBinder>& impl)
-        : BpInterface<ISurfaceComposerClient>(impl) {
+          : SafeBpInterface<ISurfaceComposerClient>(impl, "BpSurfaceComposerClient") {}
+
+    ~BpSurfaceComposerClient() override;
+
+    status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
+                           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,
+                                                                            name, width, height,
+                                                                            format, flags, parent,
+                                                                            windowType, ownerUid,
+                                                                            handle, gbp);
     }
 
-    virtual ~BpSurfaceComposerClient();
-
-    virtual status_t createSurface(const String8& name, uint32_t width,
-            uint32_t height, PixelFormat format, uint32_t flags,
-            const sp<IBinder>& parent, uint32_t windowType, uint32_t ownerUid,
-            sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeString8(name);
-        data.writeUint32(width);
-        data.writeUint32(height);
-        data.writeInt32(static_cast<int32_t>(format));
-        data.writeUint32(flags);
-        data.writeUint32(windowType);
-        data.writeUint32(ownerUid);
-        if (parent != nullptr) {
-            data.writeStrongBinder(parent);
-        }
-        remote()->transact(CREATE_SURFACE, data, &reply);
-        *handle = reply.readStrongBinder();
-        *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
-        return reply.readInt32();
+    status_t destroySurface(const sp<IBinder>& handle) override {
+        return callRemote<decltype(&ISurfaceComposerClient::destroySurface)>(Tag::DestroySurface,
+                                                                             handle);
     }
 
-    virtual status_t destroySurface(const sp<IBinder>& handle) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeStrongBinder(handle);
-        remote()->transact(DESTROY_SURFACE, data, &reply);
-        return reply.readInt32();
+    status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
+        return callRemote<decltype(
+                &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::ClearLayerFrameStats, handle);
     }
 
-    virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeStrongBinder(handle);
-        remote()->transact(CLEAR_LAYER_FRAME_STATS, data, &reply);
-        return reply.readInt32();
-    }
-
-    virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeStrongBinder(handle);
-        remote()->transact(GET_LAYER_FRAME_STATS, data, &reply);
-        reply.read(*outStats);
-        return reply.readInt32();
-    }
-
-    virtual status_t getTransformToDisplayInverse(const sp<IBinder>& handle,
-            bool* outTransformToDisplayInverse) const {
-        Parcel data, reply;
-        status_t result =
-                data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            return result;
-        }
-        result = data.writeStrongBinder(handle);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        result = remote()->transact(GET_TRANSFORM_TO_DISPLAY_INVERSE, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        int transformInverse;
-        result = reply.readInt32(&transformInverse);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        *outTransformToDisplayInverse = transformInverse != 0 ? true : false;
-        status_t result2 = reply.readInt32(&result);
-        if (result2 != NO_ERROR) {
-            return result2;
-        }
-        return result;
+    status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const override {
+        return callRemote<decltype(
+                &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GetLayerFrameStats, handle,
+                                                              outStats);
     }
 };
 
@@ -138,75 +78,29 @@
 
 // ----------------------------------------------------------------------
 
-status_t BnSurfaceComposerClient::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-     switch(code) {
-        case CREATE_SURFACE: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            String8 name = data.readString8();
-            uint32_t width = data.readUint32();
-            uint32_t height = data.readUint32();
-            PixelFormat format = static_cast<PixelFormat>(data.readInt32());
-            uint32_t createFlags = data.readUint32();
-            uint32_t windowType = data.readUint32();
-            uint32_t ownerUid = data.readUint32();
-            sp<IBinder> parent = nullptr;
-            if (data.dataAvail() > 0) {
-                parent = data.readStrongBinder();
-            }
-            sp<IBinder> handle;
-            sp<IGraphicBufferProducer> gbp;
-            status_t result = createSurface(name, width, height, format,
-                    createFlags, parent, windowType, ownerUid, &handle, &gbp);
-            reply->writeStrongBinder(handle);
-            reply->writeStrongBinder(IInterface::asBinder(gbp));
-            reply->writeInt32(result);
-            return NO_ERROR;
+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)) {
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::CreateSurface: {
+            return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
         }
-        case DESTROY_SURFACE: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            reply->writeInt32(destroySurface( data.readStrongBinder() ) );
-            return NO_ERROR;
+        case Tag::DestroySurface: {
+            return callLocal(data, reply, &ISurfaceComposerClient::destroySurface);
         }
-       case CLEAR_LAYER_FRAME_STATS: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            sp<IBinder> handle = data.readStrongBinder();
-            status_t result = clearLayerFrameStats(handle);
-            reply->writeInt32(result);
-            return NO_ERROR;
+        case Tag::ClearLayerFrameStats: {
+            return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
         }
-        case GET_LAYER_FRAME_STATS: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            sp<IBinder> handle = data.readStrongBinder();
-            FrameStats stats;
-            status_t result = getLayerFrameStats(handle, &stats);
-            reply->write(stats);
-            reply->writeInt32(result);
-            return NO_ERROR;
+        case Tag::GetLayerFrameStats: {
+            return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats);
         }
-        case GET_TRANSFORM_TO_DISPLAY_INVERSE: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            sp<IBinder> handle;
-            status_t result = data.readStrongBinder(&handle);
-            if (result != NO_ERROR) {
-                return result;
-            }
-            bool transformInverse = false;
-            result = getTransformToDisplayInverse(handle, &transformInverse);
-            if (result != NO_ERROR) {
-                return result;
-            }
-            result = reply->writeInt32(transformInverse ? 1 : 0);
-            if (result != NO_ERROR) {
-                return result;
-            }
-            result = reply->writeInt32(NO_ERROR);
-            return result;
-        }
-        default:
+        case Tag::Last:
+            // Should not be possible because of the check at the beginning of the method
             return BBinder::onTransact(code, data, reply, flags);
     }
 }
 
-}; // namespace android
+} // namespace android
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/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 088933a..56c7586 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -711,14 +711,6 @@
     return mClient->getLayerFrameStats(token, outStats);
 }
 
-status_t SurfaceComposerClient::getTransformToDisplayInverse(const sp<IBinder>& token,
-        bool* outTransformToDisplayInverse) const {
-    if (mStatus != NO_ERROR) {
-        return mStatus;
-    }
-    return mClient->getTransformToDisplayInverse(token, outTransformToDisplayInverse);
-}
-
 inline Composer& SurfaceComposerClient::getComposer() {
     return mComposer;
 }
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 1e69379..7a68f11 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -209,13 +209,6 @@
     return client->getLayerFrameStats(mHandle, outStats);
 }
 
-status_t SurfaceControl::getTransformToDisplayInverse(bool* outTransformToDisplayInverse) const {
-    status_t err = validate();
-    if (err < 0) return err;
-    const sp<SurfaceComposerClient>& client(mClient);
-    return client->getTransformToDisplayInverse(mHandle, outTransformToDisplayInverse);
-}
-
 status_t SurfaceControl::validate() const
 {
     if (mHandle==0 || mClient==0) {
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 03297ca..e35bfc9 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -538,6 +538,12 @@
     for (auto& change : mChanges->getTypeChanges()) {
         auto layerId = change.first;
         auto type = change.second;
+        if (mDevice.mLayers.count(layerId) == 0) {
+            // This should never happen but somehow does.
+            ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")",
+                  layerId);
+            continue;
+        }
         auto layer = mDevice.mLayers[layerId];
         layer->setCompositionType(type);
     }
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 1ed150b..a38b4dc 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -28,6 +28,7 @@
 #include <ui/GraphicBuffer.h>
 #include <system/graphics.h>
 #include <hardware/gralloc1.h>
+#include <grallocusage/GrallocUsageConversion.h>
 
 #include <private/android/AHardwareBufferHelpers.h>
 
@@ -100,8 +101,12 @@
     outDesc->width = gbuffer->getWidth();
     outDesc->height = gbuffer->getHeight();
     outDesc->layers = gbuffer->getLayerCount();
+
+    uint64_t producerUsage = 0;
+    uint64_t consumerUsage = 0;
+    android_convertGralloc0To1Usage(gbuffer->getUsage(), &producerUsage, &consumerUsage);
     AHardwareBuffer_convertFromGrallocUsageBits(&outDesc->usage0, &outDesc->usage1,
-            gbuffer->getUsage(), gbuffer->getUsage());
+            producerUsage, consumerUsage);
     outDesc->format = AHardwareBuffer_convertFromPixelFormat(
             static_cast<uint32_t>(gbuffer->getPixelFormat()));
 }
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/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/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 2d96638..0fa1f01 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -42,7 +42,7 @@
 
 cc_library {
     name: "libbufferhubqueue",
-    cflags = [
+    cflags: [
         "-DLOG_TAG=\"libbufferhubqueue\"",
         "-DTRACE=0",
     ],
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index bd6511d..031401a 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -146,7 +146,7 @@
     ALOGW(
         "Receives EPOLLHUP at slot: %zu, buffer event fd: %d, EPOLLHUP "
         "pending: %d",
-        slot, buffer->event_fd(), epollhup_pending_[slot]);
+        slot, buffer->event_fd(), int{epollhup_pending_[slot]});
     if (epollhup_pending_[slot]) {
       epollhup_pending_[slot] = false;
     } else {
diff --git a/libs/vr/libdvr/Android.mk b/libs/vr/libdvr/Android.mk
index 5449cb5..3c6934b 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,15 @@
     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 5aa9652..f786c29 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>
 
@@ -24,81 +25,101 @@
     DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api);
 
     // display_manager_client.h
-    dvr_api->display_manager_client_create_ = dvrDisplayManagerClientCreate;
-    dvr_api->display_manager_client_destroy_ = dvrDisplayManagerClientDestroy;
-    dvr_api->display_manager_client_get_surface_list_ =
+    dvr_api->display_manager_client_create = dvrDisplayManagerClientCreate;
+    dvr_api->display_manager_client_destroy = dvrDisplayManagerClientDestroy;
+    dvr_api->display_manager_client_get_surface_list =
         dvrDisplayManagerClientGetSurfaceList;
-    dvr_api->display_manager_client_surface_list_destroy_ =
+    dvr_api->display_manager_client_surface_list_destroy =
         dvrDisplayManagerClientSurfaceListDestroy;
-    dvr_api->display_manager_setup_pose_buffer_ =
+    dvr_api->display_manager_setup_pose_buffer =
         dvrDisplayManagerSetupPoseBuffer;
-    dvr_api->display_manager_client_surface_list_get_size_ =
+    dvr_api->display_manager_client_surface_list_get_size =
         dvrDisplayManagerClientSurfaceListGetSize;
-    dvr_api->display_manager_client_surface_list_get_surface_id_ =
+    dvr_api->display_manager_client_surface_list_get_surface_id =
         dvrDisplayManagerClientSurfaceListGetSurfaceId;
-    dvr_api->display_manager_client_get_surface_buffer_list_ =
+    dvr_api->display_manager_client_get_surface_buffer_list =
         dvrDisplayManagerClientGetSurfaceBuffers;
-    dvr_api->display_manager_client_surface_buffer_list_destroy_ =
+    dvr_api->display_manager_client_surface_buffer_list_destroy =
         dvrDisplayManagerClientSurfaceBuffersDestroy;
-    dvr_api->display_manager_client_surface_buffer_list_get_size_ =
+    dvr_api->display_manager_client_surface_buffer_list_get_size =
         dvrDisplayManagerClientSurfaceBuffersGetSize;
-    dvr_api->display_manager_client_surface_buffer_list_get_fd_ =
+    dvr_api->display_manager_client_surface_buffer_list_get_fd =
         dvrDisplayManagerClientSurfaceBuffersGetFd;
 
     // dvr_buffer.h
-    dvr_api->write_buffer_destroy_ = dvrWriteBufferDestroy;
-    dvr_api->write_buffer_get_blob_fds_ = dvrWriteBufferGetBlobFds;
-    dvr_api->write_buffer_get_AHardwareBuffer_ =
+    dvr_api->write_buffer_destroy = dvrWriteBufferDestroy;
+    dvr_api->write_buffer_get_blob_fds = dvrWriteBufferGetBlobFds;
+    dvr_api->write_buffer_get_ahardwarebuffer =
         dvrWriteBufferGetAHardwareBuffer;
-    dvr_api->write_buffer_post_ = dvrWriteBufferPost;
-    dvr_api->write_buffer_gain_ = dvrWriteBufferGain;
-    dvr_api->write_buffer_gain_async_ = dvrWriteBufferGainAsync;
+    dvr_api->write_buffer_post = dvrWriteBufferPost;
+    dvr_api->write_buffer_gain = dvrWriteBufferGain;
+    dvr_api->write_buffer_gain_async = dvrWriteBufferGainAsync;
 
-    dvr_api->read_buffer_destroy_ = dvrReadBufferDestroy;
-    dvr_api->read_buffer_get_blob_fds_ = dvrReadBufferGetBlobFds;
-    dvr_api->read_buffer_get_AHardwareBuffer_ = dvrReadBufferGetAHardwareBuffer;
-    dvr_api->read_buffer_acquire_ = dvrReadBufferAcquire;
-    dvr_api->read_buffer_release_ = dvrReadBufferRelease;
-    dvr_api->read_buffer_release_async_ = dvrReadBufferReleaseAsync;
+    dvr_api->read_buffer_destroy = dvrReadBufferDestroy;
+    dvr_api->read_buffer_get_blob_fds = dvrReadBufferGetBlobFds;
+    dvr_api->read_buffer_get_ahardwarebuffer = dvrReadBufferGetAHardwareBuffer;
+    dvr_api->read_buffer_acquire = dvrReadBufferAcquire;
+    dvr_api->read_buffer_release = dvrReadBufferRelease;
+    dvr_api->read_buffer_release_async = dvrReadBufferReleaseAsync;
 
     // dvr_buffer_queue.h
-    dvr_api->write_buffer_queue_destroy_ = dvrWriteBufferQueueDestroy;
-    dvr_api->write_buffer_queue_get_capacity_ = dvrWriteBufferQueueGetCapacity;
-    dvr_api->write_buffer_queue_get_external_surface_ =
+    dvr_api->write_buffer_queue_destroy = dvrWriteBufferQueueDestroy;
+    dvr_api->write_buffer_queue_get_capacity = dvrWriteBufferQueueGetCapacity;
+    dvr_api->write_buffer_queue_get_external_surface =
         dvrWriteBufferQueueGetExternalSurface;
-    dvr_api->write_buffer_queue_create_read_queue_ =
+    dvr_api->write_buffer_queue_create_read_queue =
         dvrWriteBufferQueueCreateReadQueue;
-    dvr_api->write_buffer_queue_dequeue_ = dvrWriteBufferQueueDequeue;
-    dvr_api->read_buffer_queue_destroy_ = dvrReadBufferQueueDestroy;
-    dvr_api->read_buffer_queue_get_capacity_ = dvrReadBufferQueueGetCapacity;
-    dvr_api->read_buffer_queue_create_read_queue_ =
+    dvr_api->write_buffer_queue_dequeue = dvrWriteBufferQueueDequeue;
+    dvr_api->read_buffer_queue_destroy = dvrReadBufferQueueDestroy;
+    dvr_api->read_buffer_queue_get_capacity = dvrReadBufferQueueGetCapacity;
+    dvr_api->read_buffer_queue_create_read_queue =
         dvrReadBufferQueueCreateReadQueue;
     dvr_api->read_buffer_queue_dequeue = dvrReadBufferQueueDequeue;
 
     // dvr_surface.h
-    dvr_api->get_pose_buffer_ = dvrGetPoseBuffer;
-    dvr_api->surface_create_ = dvrSurfaceCreate;
-    dvr_api->surface_get_write_buffer_queue_ = dvrSurfaceGetWriteBufferQueue;
+    dvr_api->get_pose_buffer = dvrGetPoseBuffer;
+    dvr_api->surface_create = dvrSurfaceCreate;
+    dvr_api->surface_get_write_buffer_queue = dvrSurfaceGetWriteBufferQueue;
 
     // vsync_client_api.h
-    dvr_api->vsync_client_create_ = dvr_vsync_client_create;
-    dvr_api->vsync_client_destroy_ = dvr_vsync_client_destroy;
-    dvr_api->vsync_client_get_sched_info_ = dvr_vsync_client_get_sched_info;
+    dvr_api->vsync_client_create = dvr_vsync_client_create;
+    dvr_api->vsync_client_destroy = dvr_vsync_client_destroy;
+    dvr_api->vsync_client_get_sched_info = dvr_vsync_client_get_sched_info;
 
     // pose_client.h
-    dvr_api->pose_client_create_ = dvrPoseCreate;
-    dvr_api->pose_client_destroy_ = dvrPoseDestroy;
-    dvr_api->pose_get_ = dvrPoseGet;
-    dvr_api->pose_get_vsync_count_ = dvrPoseGetVsyncCount;
-    dvr_api->pose_get_controller_ = dvrPoseGetController;
+    dvr_api->pose_client_create = dvrPoseCreate;
+    dvr_api->pose_client_destroy = dvrPoseDestroy;
+    dvr_api->pose_get = dvrPoseGet;
+    dvr_api->pose_get_vsync_count = dvrPoseGetVsyncCount;
+    dvr_api->pose_get_controller = dvrPoseGetController;
 
     // virtual_touchpad_client.h
-    dvr_api->virtual_touchpad_create_ = dvrVirtualTouchpadCreate;
-    dvr_api->virtual_touchpad_destroy_ = dvrVirtualTouchpadDestroy;
-    dvr_api->virtual_touchpad_attach_ = dvrVirtualTouchpadAttach;
-    dvr_api->virtual_touchpad_detach_ = dvrVirtualTouchpadDetach;
-    dvr_api->virtual_touchpad_touch_ = dvrVirtualTouchpadTouch;
-    dvr_api->virtual_touchpad_button_state_ = dvrVirtualTouchpadButtonState;
+    dvr_api->virtual_touchpad_create = dvrVirtualTouchpadCreate;
+    dvr_api->virtual_touchpad_destroy = dvrVirtualTouchpadDestroy;
+    dvr_api->virtual_touchpad_attach = dvrVirtualTouchpadAttach;
+    dvr_api->virtual_touchpad_detach = dvrVirtualTouchpadDetach;
+    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_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;
   }
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 bee4d66..053382f 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <dvr/dvr_hardware_composer_defs.h>
 #include <jni.h>
 
 #ifdef __cplusplus
@@ -144,82 +145,132 @@
 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_;
-  DvrDisplayManagerClientDestroyPtr display_manager_client_destroy_;
+  DvrDisplayManagerClientCreatePtr display_manager_client_create;
+  DvrDisplayManagerClientDestroyPtr display_manager_client_destroy;
   DvrDisplayManagerClientGetSurfaceListPtr
-      display_manager_client_get_surface_list_;
+      display_manager_client_get_surface_list;
   DvrDisplayManagerClientSurfaceListDestroyPtr
-      display_manager_client_surface_list_destroy_;
-  DvrDisplayManagerSetupPoseBufferPtr display_manager_setup_pose_buffer_;
+      display_manager_client_surface_list_destroy;
+  DvrDisplayManagerSetupPoseBufferPtr display_manager_setup_pose_buffer;
   DvrDisplayManagerClientSurfaceListGetSizePtr
-      display_manager_client_surface_list_get_size_;
+      display_manager_client_surface_list_get_size;
   DvrDisplayManagerClientSurfaceListGetSurfaceIdPtr
-      display_manager_client_surface_list_get_surface_id_;
+      display_manager_client_surface_list_get_surface_id;
   DvrDisplayManagerClientGetSurfaceBufferListPtr
-      display_manager_client_get_surface_buffer_list_;
+      display_manager_client_get_surface_buffer_list;
   DvrDisplayManagerClientSurfaceBufferListDestroyPtr
-      display_manager_client_surface_buffer_list_destroy_;
+      display_manager_client_surface_buffer_list_destroy;
   DvrDisplayManagerClientSurfaceBufferListGetSizePtr
-      display_manager_client_surface_buffer_list_get_size_;
+      display_manager_client_surface_buffer_list_get_size;
   DvrDisplayManagerClientSurfaceBufferListGetFdPtr
-      display_manager_client_surface_buffer_list_get_fd_;
+      display_manager_client_surface_buffer_list_get_fd;
 
   // Write buffer
-  DvrWriteBufferDestroyPtr write_buffer_destroy_;
-  DvrWriteBufferGetBlobFdsPtr write_buffer_get_blob_fds_;
-  DvrWriteBufferGetAHardwareBufferPtr write_buffer_get_AHardwareBuffer_;
-  DvrWriteBufferPostPtr write_buffer_post_;
-  DvrWriteBufferGainPtr write_buffer_gain_;
-  DvrWriteBufferGainAsyncPtr write_buffer_gain_async_;
+  DvrWriteBufferDestroyPtr write_buffer_destroy;
+  DvrWriteBufferGetBlobFdsPtr write_buffer_get_blob_fds;
+  DvrWriteBufferGetAHardwareBufferPtr write_buffer_get_ahardwarebuffer;
+  DvrWriteBufferPostPtr write_buffer_post;
+  DvrWriteBufferGainPtr write_buffer_gain;
+  DvrWriteBufferGainAsyncPtr write_buffer_gain_async;
 
   // Read buffer
-  DvrReadBufferDestroyPtr read_buffer_destroy_;
-  DvrReadBufferGetBlobFdsPtr read_buffer_get_blob_fds_;
-  DvrReadBufferGetAHardwareBufferPtr read_buffer_get_AHardwareBuffer_;
-  DvrReadBufferAcquirePtr read_buffer_acquire_;
-  DvrReadBufferReleasePtr read_buffer_release_;
-  DvrReadBufferReleaseAsyncPtr read_buffer_release_async_;
+  DvrReadBufferDestroyPtr read_buffer_destroy;
+  DvrReadBufferGetBlobFdsPtr read_buffer_get_blob_fds;
+  DvrReadBufferGetAHardwareBufferPtr read_buffer_get_ahardwarebuffer;
+  DvrReadBufferAcquirePtr read_buffer_acquire;
+  DvrReadBufferReleasePtr read_buffer_release;
+  DvrReadBufferReleaseAsyncPtr read_buffer_release_async;
 
   // Write buffer queue
-  DvrWriteBufferQueueDestroyPtr write_buffer_queue_destroy_;
-  DvrWriteBufferQueueGetCapacityPtr write_buffer_queue_get_capacity_;
+  DvrWriteBufferQueueDestroyPtr write_buffer_queue_destroy;
+  DvrWriteBufferQueueGetCapacityPtr write_buffer_queue_get_capacity;
   DvrWriteBufferQueueGetExternalSurfacePtr
-      write_buffer_queue_get_external_surface_;
-  DvrWriteBufferQueueCreateReadQueuePtr write_buffer_queue_create_read_queue_;
-  DvrWriteBufferQueueDequeuePtr write_buffer_queue_dequeue_;
+      write_buffer_queue_get_external_surface;
+  DvrWriteBufferQueueCreateReadQueuePtr write_buffer_queue_create_read_queue;
+  DvrWriteBufferQueueDequeuePtr write_buffer_queue_dequeue;
 
   // Read buffer queue
-  DvrReadBufferQueueDestroyPtr read_buffer_queue_destroy_;
-  DvrReadBufferQueueGetCapacityPtr read_buffer_queue_get_capacity_;
-  DvrReadBufferQueueCreateReadQueuePtr read_buffer_queue_create_read_queue_;
+  DvrReadBufferQueueDestroyPtr read_buffer_queue_destroy;
+  DvrReadBufferQueueGetCapacityPtr read_buffer_queue_get_capacity;
+  DvrReadBufferQueueCreateReadQueuePtr read_buffer_queue_create_read_queue;
   DvrReadBufferQueueDequeuePtr read_buffer_queue_dequeue;
 
   // V-Sync client
-  DvrVSyncClientCreatePtr vsync_client_create_;
-  DvrVSyncClientDestroyPtr vsync_client_destroy_;
-  DvrVSyncClientGetSchedInfoPtr vsync_client_get_sched_info_;
+  DvrVSyncClientCreatePtr vsync_client_create;
+  DvrVSyncClientDestroyPtr vsync_client_destroy;
+  DvrVSyncClientGetSchedInfoPtr vsync_client_get_sched_info;
 
   // Display surface
-  DvrGetPoseBufferPtr get_pose_buffer_;
-  DvrSurfaceCreatePtr surface_create_;
-  DvrSurfaceGetWriteBufferQueuePtr surface_get_write_buffer_queue_;
+  DvrGetPoseBufferPtr get_pose_buffer;
+  DvrSurfaceCreatePtr surface_create;
+  DvrSurfaceGetWriteBufferQueuePtr surface_get_write_buffer_queue;
 
   // Pose client
-  DvrPoseClientCreatePtr pose_client_create_;
-  DvrPoseClientDestroyPtr pose_client_destroy_;
-  DvrPoseGetPtr pose_get_;
-  DvrPoseGetVsyncCountPtr pose_get_vsync_count_;
-  DvrPoseGetControllerPtr pose_get_controller_;
+  DvrPoseClientCreatePtr pose_client_create;
+  DvrPoseClientDestroyPtr pose_client_destroy;
+  DvrPoseGetPtr pose_get;
+  DvrPoseGetVsyncCountPtr pose_get_vsync_count;
+  DvrPoseGetControllerPtr pose_get_controller;
 
   // Virtual touchpad client
-  DvrVirtualTouchpadCreatePtr virtual_touchpad_create_;
-  DvrVirtualTouchpadDestroyPtr virtual_touchpad_destroy_;
-  DvrVirtualTouchpadAttachPtr virtual_touchpad_attach_;
-  DvrVirtualTouchpadDetachPtr virtual_touchpad_detach_;
-  DvrVirtualTouchpadTouchPtr virtual_touchpad_touch_;
-  DvrVirtualTouchpadButtonStatePtr virtual_touchpad_button_state_;
+  DvrVirtualTouchpadCreatePtr virtual_touchpad_create;
+  DvrVirtualTouchpadDestroyPtr virtual_touchpad_destroy;
+  DvrVirtualTouchpadAttachPtr virtual_touchpad_attach;
+  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/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/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..9a012ed 100644
--- a/libs/vr/libpdx/private/pdx/rpc/serialization.h
+++ b/libs/vr/libpdx/private/pdx/rpc/serialization.h
@@ -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);
 }
 
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_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..9f308ec 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -41,6 +41,8 @@
         "libpdx",
     ],
     shared_libs: [
+        "libbase",
+        "libcutils",
         "liblog",
         "libutils",
     ],
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp
index 1879127..f059453 100644
--- a/libs/vr/libpdx_uds/client_channel_factory.cpp
+++ b/libs/vr/libpdx_uds/client_channel_factory.cpp
@@ -6,10 +6,16 @@
 #include <sys/un.h>
 #include <unistd.h>
 
+#include <chrono>
+#include <thread>
+
 #include <uds/channel_manager.h>
 #include <uds/client_channel.h>
 #include <uds/ipc_helper.h>
 
+using std::chrono::duration_cast;
+using std::chrono::steady_clock;
+
 namespace android {
 namespace pdx {
 namespace uds {
@@ -41,13 +47,11 @@
 
 Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
     int64_t timeout_ms) const {
-  auto status = WaitForEndpoint(endpoint_path_, timeout_ms);
-  if (!status)
-    return ErrorStatus(status.error());
+  Status<void> status;
 
   LocalHandle socket_fd{socket(AF_UNIX, SOCK_STREAM, 0)};
   if (!socket_fd) {
-    ALOGE("ClientChannelFactory::Connect: socket error %s", strerror(errno));
+    ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno));
     return ErrorStatus(errno);
   }
 
@@ -56,16 +60,55 @@
   strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path));
   remote.sun_path[sizeof(remote.sun_path) - 1] = '\0';
 
-  int ret = RETRY_EINTR(connect(
-      socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
-  if (ret == -1) {
-    ALOGE(
-        "ClientChannelFactory::Connect: Failed to initialize connection when "
-        "connecting %s",
-        strerror(errno));
-    return ErrorStatus(errno);
-  }
+  bool use_timeout = (timeout_ms >= 0);
+  auto now = steady_clock::now();
+  auto time_end = now + std::chrono::milliseconds{timeout_ms};
 
+  bool connected = false;
+  while (!connected) {
+    int64_t timeout = -1;
+    if (use_timeout) {
+      auto remaining = time_end - now;
+      timeout = duration_cast<std::chrono::milliseconds>(remaining).count();
+      if (timeout < 0)
+        return ErrorStatus(ETIMEDOUT);
+    }
+    ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path);
+    status = WaitForEndpoint(endpoint_path_, timeout);
+    if (!status)
+      return ErrorStatus(status.error());
+
+    ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path);
+    int ret = RETRY_EINTR(connect(
+        socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
+    if (ret == -1) {
+      ALOGD("ClientChannelFactory: Connect error %d: %s", errno,
+            strerror(errno));
+      if (errno == ECONNREFUSED) {
+        // Connection refused can be the result of connecting too early (the
+        // service socket is created but not being listened to yet).
+        ALOGD("ClientChannelFactory: Connection refused, waiting...");
+        using namespace std::literals::chrono_literals;
+        std::this_thread::sleep_for(100ms);
+      } else if (errno != ENOENT && errno != ENOTDIR) {
+        // ENOENT/ENOTDIR might mean that the socket file/directory containing
+        // it has been just deleted. Try to wait for its creation and do not
+        // return an error immediately.
+        ALOGE(
+            "ClientChannelFactory::Connect: Failed to initialize connection "
+            "when connecting: %s",
+            strerror(errno));
+        return ErrorStatus(errno);
+      }
+    } else {
+      connected = true;
+    }
+    if (use_timeout)
+      now = steady_clock::now();
+  }  // while (!connected)
+
+  ALOGD("ClientChannelFactory: Connected successfully to %s...",
+        remote.sun_path);
   RequestHeader<BorrowedHandle> request;
   InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
   status = SendData(socket_fd.Get(), request);
diff --git a/libs/vr/libpdx_uds/ipc_helper.cpp b/libs/vr/libpdx_uds/ipc_helper.cpp
index ee7299e..fe5c986 100644
--- a/libs/vr/libpdx_uds/ipc_helper.cpp
+++ b/libs/vr/libpdx_uds/ipc_helper.cpp
@@ -87,7 +87,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 +97,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,21 +108,21 @@
   }
 }
 
-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) {
diff --git a/libs/vr/libpdx_uds/private/uds/ipc_helper.h b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
index 00f3490..80530bf 100644
--- a/libs/vr/libpdx_uds/private/uds/ipc_helper.h
+++ b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
@@ -33,13 +33,14 @@
   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:
diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
index 3ec8519..9d038cb 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:
@@ -117,7 +123,7 @@
   Status<void> OnNewChannel(LocalHandle channel_fd);
   Status<ChannelData*> OnNewChannelLocked(LocalHandle channel_fd,
                                           Channel* channel_state);
-  int CloseChannelLocked(int channel_id);
+  Status<void> CloseChannelLocked(int channel_id);
   Status<void> ReenableEpollEvent(int fd);
   Channel* GetChannelState(int channel_id);
   int GetChannelSocketFd(int channel_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_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 7bf753d..f89b8a8 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -19,6 +19,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 +52,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 +71,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 +86,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 +96,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,
@@ -214,18 +215,18 @@
   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) {
@@ -269,44 +270,46 @@
   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(int 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;
+    return ErrorStatus{EINVAL};
 
-  int ret = 0;
+  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;
+    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;
+  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,
@@ -337,17 +340,19 @@
   *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();
 
   // 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());
+  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,13 +362,6 @@
   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) {
   std::lock_guard<std::mutex> autolock(channel_mutex_);
   auto channel_data = channels_.find(channel_id);
@@ -464,7 +462,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 +472,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_.Get());
   }
 
   int channel_id = event.data.fd;
   if (event.events & (EPOLLRDHUP | EPOLLHUP)) {
     BuildCloseMessage(channel_id, message);
-    return 0;
+    return {};
   }
 
-  auto status = ReceiveMessageForChannel(channel_id, message);
-  if (!status)
-    return -status.error();
-  return 0;
+  return ReceiveMessageForChannel(channel_id, message);
 }
 
-int Endpoint::MessageReply(Message* message, int return_code) {
+Status<void> 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;
+    return ErrorStatus{EBADF};
 
   auto* state = static_cast<MessageState*>(message->GetState());
   switch (message->GetOp()) {
@@ -515,12 +509,17 @@
       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(
+            BorrowedHandle{GetChannelEventFd(channel_socket)});
+        state->response_data.clear();  // Just in case...
+        if (!push_status)
+          return push_status.error_status();
+        return_code = push_status.get();
+      }
       break;
   }
 
@@ -535,76 +534,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 +629,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 +641,14 @@
   return std::unique_ptr<Endpoint>(new Endpoint(endpoint_path, blocking));
 }
 
+std::unique_ptr<Endpoint> Endpoint::CreateAndBindSocket(
+    const std::string& endpoint_path, bool blocking) {
+  // TODO(avakulenko): When Endpoint can differentiate between absolute paths
+  // and relative paths/socket names created by the init process, change this
+  // code to reflect the fact that we want to use absolute paths here.
+  return std::unique_ptr<Endpoint>(new Endpoint(endpoint_path, blocking));
+}
+
 }  // 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/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..3750ea3 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(
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/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/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/Client.cpp b/services/surfaceflinger/Client.cpp
index 9ddae2b..e9a2513 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -210,15 +210,5 @@
     return NO_ERROR;
 }
 
-status_t Client::getTransformToDisplayInverse(const sp<IBinder>& handle,
-        bool* outTransformToDisplayInverse) const {
-    sp<Layer> layer = getLayerUser(handle);
-    if (layer == NULL) {
-        return NAME_NOT_FOUND;
-    }
-    *outTransformToDisplayInverse = layer->getTransformToDisplayInverse();
-    return NO_ERROR;
-}
-
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 141f6c7..b5f98b8 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -67,8 +67,6 @@
     virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
 
     virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
-    virtual status_t getTransformToDisplayInverse(
-            const sp<IBinder>& handle, bool* outTransformToDisplayInverse) const;
 
     virtual status_t onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ac7e083..16d8160 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -505,7 +505,7 @@
     // which means using the inverse of the current transform set on the
     // SurfaceFlingerConsumer.
     uint32_t invTransform = mCurrentTransform;
-    if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+    if (getTransformToDisplayInverse()) {
         /*
          * the code below applies the primary display's inverse transform to the
          * buffer
@@ -713,7 +713,7 @@
     const Transform bufferOrientation(mCurrentTransform);
     Transform transform(tr * t * bufferOrientation);
 
-    if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+    if (getTransformToDisplayInverse()) {
         /*
          * the code below applies the primary display's inverse transform to the
          * buffer
@@ -725,8 +725,14 @@
             invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
                     NATIVE_WINDOW_TRANSFORM_FLIP_H;
         }
-        // and apply to the current transform
-        transform = Transform(invTransform) * transform;
+
+        /*
+         * Here we cancel out the orientation component of the WM transform.
+         * The scaling and translate components are already included in our bounds
+         * computation so it's enough to just omit it in the composition.
+         * See comment in onDraw with ref to b/36727915 for why.
+         */
+        transform = Transform(invTransform) * tr * bufferOrientation;
     }
 
     // this gives us only the "orientation" component of the transform
@@ -987,6 +993,24 @@
     onDraw(hw, Region(hw->bounds()), false);
 }
 
+static constexpr mat4 inverseOrientation(uint32_t transform) {
+    const mat4 flipH(-1,0,0,0,  0,1,0,0, 0,0,1,0, 1,0,0,1);
+    const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
+    const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
+    mat4 tr;
+
+    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+        tr = tr * rot90;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+        tr = tr * flipH;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+        tr = tr * flipV;
+    }
+    return inverse(tr);
+}
+
 void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
         bool useIdentityTransform) const
 {
@@ -1041,30 +1065,29 @@
         mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
         mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
 
-        if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+        if (getTransformToDisplayInverse()) {
 
             /*
              * the code below applies the primary display's inverse transform to
              * the texture transform
              */
-
-            // create a 4x4 transform matrix from the display transform flags
-            const mat4 flipH(-1,0,0,0,  0,1,0,0, 0,0,1,0, 1,0,0,1);
-            const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
-            const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
-
-            mat4 tr;
             uint32_t transform =
                     DisplayDevice::getPrimaryDisplayOrientationTransform();
-            if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90)
-                tr = tr * rot90;
-            if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H)
-                tr = tr * flipH;
-            if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V)
-                tr = tr * flipV;
+            mat4 tr = inverseOrientation(transform);
 
-            // calculate the inverse
-            tr = inverse(tr);
+            /**
+             * TODO(b/36727915): This is basically a hack.
+             *
+             * Ensure that regardless of the parent transformation,
+             * this buffer is always transformed from native display
+             * orientation to display orientation. For example, in the case
+             * of a camera where the buffer remains in native orientation,
+             * we want the pixels to always be upright.
+             */
+            if (getParent() != nullptr) {
+                const auto parentTransform = getParent()->getTransform();
+                tr = tr * inverseOrientation(parentTransform.getOrientation());
+            }
 
             // and finally apply it to the original texture matrix
             const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index e3dbecc..7564269 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -382,6 +382,7 @@
         attribs[EGL_RED_SIZE]                   = 8;
         attribs[EGL_GREEN_SIZE]                 = 8;
         attribs[EGL_BLUE_SIZE]                  = 8;
+        attribs[EGL_ALPHA_SIZE]                 = 8;
         wantedAttribute                         = EGL_NONE;
         wantedAttributeValue                    = EGL_NONE;
     } else {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f82b363..834c1c4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1903,7 +1903,8 @@
                         // etc.) but no internal state (i.e. a DisplayDevice).
                         if (state.surface != NULL) {
 
-                            if (mUseHwcVirtualDisplays) {
+                            // Allow VR composer to use virtual displays.
+                            if (mUseHwcVirtualDisplays || mHwc == mVrHwc) {
                                 int width = 0;
                                 int status = state.surface->query(
                                         NATIVE_WINDOW_WIDTH, &width);
@@ -2839,15 +2840,17 @@
 
     sp<Layer> layer;
 
+    String8 uniqueName = getUniqueLayerName(name);
+
     switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
         case ISurfaceComposerClient::eFXSurfaceNormal:
             result = createNormalLayer(client,
-                    name, w, h, flags, format,
+                    uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceDim:
             result = createDimLayer(client,
-                    name, w, h, flags,
+                    uniqueName, w, h, flags,
                     handle, gbp, &layer);
             break;
         default:
@@ -2871,6 +2874,30 @@
     return result;
 }
 
+String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
+{
+    bool matchFound = true;
+    uint32_t dupeCounter = 0;
+
+    // Tack on our counter whether there is a hit or not, so everyone gets a tag
+    String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
+
+    // Loop over layers until we're sure there is no matching name
+    while (matchFound) {
+        matchFound = false;
+        mDrawingState.traverseInZOrder([&](Layer* layer) {
+            if (layer->getName() == uniqueName) {
+                matchFound = true;
+                uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
+            }
+        });
+    }
+
+    ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+
+    return uniqueName;
+}
+
 status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 581bbfd..4ecbddd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -364,6 +364,8 @@
             uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
             sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
 
+    String8 getUniqueLayerName(const String8& name);
+
     // called in response to the window-manager calling
     // ISurfaceComposerClient::destroySurface()
     status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle);
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index c26847f..a6c0b9c 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2637,15 +2637,17 @@
 
     sp<Layer> layer;
 
+    String8 uniqueName = getUniqueLayerName(name);
+
     switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
         case ISurfaceComposerClient::eFXSurfaceNormal:
             result = createNormalLayer(client,
-                    name, w, h, flags, format,
+                    uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceDim:
             result = createDimLayer(client,
-                    name, w, h, flags,
+                    uniqueName, w, h, flags,
                     handle, gbp, &layer);
             break;
         default:
@@ -2669,6 +2671,30 @@
     return result;
 }
 
+String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
+{
+    bool matchFound = true;
+    uint32_t dupeCounter = 0;
+
+    // Tack on our counter whether there is a hit or not, so everyone gets a tag
+    String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
+
+    // Loop over layers until we're sure there is no matching name
+    while (matchFound) {
+        matchFound = false;
+        mDrawingState.traverseInZOrder([&](Layer* layer) {
+            if (layer->getName() == uniqueName) {
+                matchFound = true;
+                uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
+            }
+        });
+    }
+
+    ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+
+    return uniqueName;
+}
+
 status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index 435aa0c..0b482f7 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -1,5 +1,5 @@
 service surfaceflinger /system/bin/surfaceflinger
-    class core
+    class core animation
     user system
     group graphics drmrpc readproc
     onrestart restart zygote
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index c1a0b6f..b3d777e 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -30,7 +30,6 @@
 sharedLibraries := \
 	libbase \
 	libcutils \
-	libhardware \
 	liblog \
 	libsync \
 	libutils \
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 80efcf8..de4950e 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -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);
@@ -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..8a7dca8 100644
--- a/services/vr/bufferhubd/buffer_hub.h
+++ b/services/vr/bufferhubd/buffer_hub.h
@@ -141,7 +141,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,
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 98a419f..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();
   }
 
@@ -238,7 +238,7 @@
 
   ClearAvailable();
   producer_owns_ = true;
-  post_fence_.get_fd();
+  post_fence_.close();
   return std::move(returned_fence_);
 }
 
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp
index 08f1e9d..7952642 100644
--- a/services/vr/bufferhubd/producer_queue_channel.cpp
+++ b/services/vr/bufferhubd/producer_queue_channel.cpp
@@ -97,18 +97,18 @@
         "ProducerQueueChannel::OnCreateConsumerQueue: failed to push consumer "
         "channel: %s",
         status.GetErrorMessage().c_str());
-    REPLY_ERROR_RETURN(message, ENOMEM, {});
+    REPLY_ERROR_RETURN(message, status.error(), {});
   }
 
-  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());
+    REPLY_ERROR_RETURN(message, channel_status.error(), {});
   }
 
   return std::make_pair(status.take(), meta_size_bytes_);
@@ -214,12 +214,13 @@
       "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));
+        channel_status.GetErrorMessage().c_str());
     return {};
   }
 
@@ -252,7 +253,7 @@
   return {std::move(buffer_handle), slot};
 }
 
-int ProducerQueueChannel::OnProducerQueueDetachBuffer(Message& message,
+int ProducerQueueChannel::OnProducerQueueDetachBuffer(Message& /*message*/,
                                                       size_t slot) {
   if (buffers_[slot].expired()) {
     ALOGE(
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 1601c7f..629d65b 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -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_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
index cb3e49d..45eabca 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
@@ -19,6 +19,12 @@
   status_t ret = parcel->writeUint64(frame_.display_id);
   if (ret != OK) return ret;
 
+  ret = parcel->writeInt32(frame_.display_width);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(frame_.display_height);
+  if (ret != OK) return ret;
+
   ret = parcel->writeBool(frame_.removed);
   if (ret != OK) return ret;
 
@@ -35,6 +41,12 @@
   status_t ret = parcel->readUint64(&frame_.display_id);
   if (ret != OK) return ret;
 
+  ret = parcel->readInt32(&frame_.display_width);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(&frame_.display_height);
+  if (ret != OK) return ret;
+
   ret = parcel->readBool(&frame_.removed);
   if (ret != OK) return ret;
 
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
index cfc2708..d082f4b 100644
--- a/services/vr/hardware_composer/tests/vr_composer_test.cpp
+++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp
@@ -104,6 +104,8 @@
   ComposerView::Frame frame;
   frame.display_id = 1;
   frame.removed = false;
+  frame.display_width = 600;
+  frame.display_height = 400;
   frame.layers.push_back(ComposerView::ComposerLayer{
     .id = 1,
     .buffer = CreateBuffer(),
@@ -120,6 +122,8 @@
 
   ComposerView::Frame received_frame = callback->last_frame();
   ASSERT_EQ(frame.display_id, received_frame.display_id);
+  ASSERT_EQ(frame.display_width, received_frame.display_width);
+  ASSERT_EQ(frame.display_height, received_frame.display_height);
   ASSERT_EQ(frame.removed, received_frame.removed);
   ASSERT_EQ(1u, received_frame.layers.size());
   ASSERT_EQ(frame.layers[0].id, received_frame.layers[0].id);
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/sensord/pose_service.cpp b/services/vr/sensord/pose_service.cpp
index 2c4fc30..3cd5297 100644
--- a/services/vr/sensord/pose_service.cpp
+++ b/services/vr/sensord/pose_service.cpp
@@ -476,8 +476,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 +495,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 +527,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..fdd29b5 100644
--- a/services/vr/sensord/pose_service.h
+++ b/services/vr/sensord/pose_service.h
@@ -27,7 +27,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.
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/vr_window_manager/Android.bp b/services/vr/vr_window_manager/Android.bp
index a7a341c..0406331 100644
--- a/services/vr/vr_window_manager/Android.bp
+++ b/services/vr/vr_window_manager/Android.bp
@@ -41,6 +41,7 @@
     "libperformance",
     "libpdx_default_transport",
     "libcutils",
+    "libvr_hwc-binder",
     "libvr_manager",
     "libvirtualtouchpadclient",
 ]
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 a5f633e..d142729 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -80,9 +80,35 @@
   return buffer;
 }
 
+void GetPrimaryDisplaySize(int32_t* width, int32_t* height) {
+  *width = 1080;
+  *height = 1920;
+
+  int error = 0;
+  auto display_client = DisplayClient::Create(&error);
+  SystemDisplayMetrics metrics;
+
+  if (error) {
+    ALOGE("Could not connect to display service : %s(%d)", strerror(error),
+          error);
+    return;
+  }
+
+  error = display_client->GetDisplayMetrics(&metrics);
+  if (error) {
+    ALOGE("Could not get display metrics from display service : %s(%d)",
+          strerror(error), error);
+    return;
+  }
+
+  *width = metrics.display_native_width;
+  *height = metrics.display_native_height;
+}
+
 }  // namespace
 
-HwcDisplay::HwcDisplay() {}
+HwcDisplay::HwcDisplay(int32_t width, int32_t height)
+    : width_(width), height_(height) {}
 
 HwcDisplay::~HwcDisplay() {}
 
@@ -221,7 +247,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // VrHwcClient
 
-VrHwc::VrHwc() { displays_[kDefaultDisplayId].reset(new HwcDisplay()); }
+VrHwc::VrHwc() {}
 
 VrHwc::~VrHwc() {}
 
@@ -234,6 +260,14 @@
 
 void VrHwc::enableCallback(bool enable) {
   if (enable && client_ != nullptr) {
+    {
+      int32_t width, height;
+      GetPrimaryDisplaySize(&width, &height);
+      std::lock_guard<std::mutex> guard(mutex_);
+      // Create the primary display late to avoid initialization issues between
+      // VR HWC and SurfaceFlinger.
+      displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
+    }
     client_.promote()->onHotplug(kDefaultDisplayId,
                                  IComposerCallback::Connection::CONNECTED);
   }
@@ -245,7 +279,7 @@
                                   PixelFormat* format, Display* outDisplay) {
   *format = PixelFormat::RGBA_8888;
   *outDisplay = display_count_;
-  displays_[display_count_].reset(new HwcDisplay());
+  displays_[display_count_].reset(new HwcDisplay(width, height));
   display_count_++;
   return Error::NONE;
 }
@@ -307,41 +341,20 @@
                                  IComposerClient::Attribute attribute,
                                  int32_t* outValue) {
   std::lock_guard<std::mutex> guard(mutex_);
-  if (!FindDisplay(display))
+  auto display_ptr = FindDisplay(display);
+  if (!display_ptr) {
     return Error::BAD_DISPLAY;
+  }
   if (config != kDefaultConfigId) {
     return Error::BAD_CONFIG;
   }
 
-  int error = 0;
-  auto display_client = DisplayClient::Create(&error);
-  SystemDisplayMetrics metrics;
-
-  if (error) {
-    ALOGE("Could not connect to display service : %s(%d)", strerror(error),
-          error);
-  } else {
-    error = display_client->GetDisplayMetrics(&metrics);
-
-    if (error) {
-      ALOGE("Could not get display metrics from display service : %s(%d)",
-            strerror(error), error);
-    }
-  }
-
-  if (error) {
-    metrics.display_native_width = 1080;
-    metrics.display_native_height = 1920;
-    ALOGI("Setting display metrics to default : width=%d height=%d",
-          metrics.display_native_width, metrics.display_native_height);
-  }
-
   switch (attribute) {
     case IComposerClient::Attribute::WIDTH:
-      *outValue = metrics.display_native_width;
+      *outValue = display_ptr->width();
       break;
     case IComposerClient::Attribute::HEIGHT:
-      *outValue = metrics.display_native_height;
+      *outValue = display_ptr->height();
       break;
     case IComposerClient::Attribute::VSYNC_PERIOD:
       *outValue = 1000 * 1000 * 1000 / 30;  // 30fps
@@ -509,6 +522,8 @@
   std::vector<Layer> last_frame_layers;
   Error status = display_ptr->GetFrame(&frame.layers);
   frame.display_id = display;
+  frame.display_width = display_ptr->width();
+  frame.display_height = display_ptr->height();
   if (status != Error::NONE)
     return status;
 
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
index 3c76120..bfca9a6 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
@@ -74,6 +74,8 @@
     // being removed, or left false in the case of a normal frame. The upper
     // layer tracks display IDs and will handle new ones showing up.
     bool removed = false;
+    int32_t display_width;
+    int32_t display_height;
     std::vector<ComposerLayer> layers;
   };
 
@@ -107,9 +109,12 @@
 
 class HwcDisplay {
  public:
-  HwcDisplay();
+  HwcDisplay(int32_t width, int32_t height);
   ~HwcDisplay();
 
+  int32_t width() const { return width_; }
+  int32_t height() const { return height_; }
+
   HwcLayer* CreateLayer();
   bool DestroyLayer(Layer id);
   HwcLayer* GetLayer(Layer id);
@@ -138,6 +143,9 @@
   // Layer ID generator.
   uint64_t layer_ids_ = 1;
 
+  int32_t width_;
+  int32_t height_;
+
   HwcDisplay(const HwcDisplay&) = delete;
   void operator=(const HwcDisplay&) = delete;
 };
diff --git a/services/vr/vr_window_manager/display_view.cpp b/services/vr/vr_window_manager/display_view.cpp
index 311e27f..52984b7 100644
--- a/services/vr/vr_window_manager/display_view.cpp
+++ b/services/vr/vr_window_manager/display_view.cpp
@@ -168,8 +168,7 @@
 
 void DisplayView::DrawEye(EyeType /* eye */, const mat4& perspective,
                           const mat4& eye_matrix, const mat4& head_matrix,
-                          const vec2& size, float fade_value) {
-  size_ = size;
+                          float fade_value) {
   scale_ = GetScalingMatrix(size_.x(), size_.y());
 
   DrawOverlays(perspective, eye_matrix, head_matrix, fade_value);
@@ -204,6 +203,7 @@
 base::unique_fd DisplayView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
                                      bool debug_mode, bool is_vr_active,
                                      bool* showing) {
+  size_ = vec2(frame->display_width(), frame->display_height());
   uint32_t app = current_vr_app_;
   ViewMode visibility = CalculateVisibilityFromLayerConfig(*frame.get(), &app);
 
diff --git a/services/vr/vr_window_manager/display_view.h b/services/vr/vr_window_manager/display_view.h
index aaf4677..ad624c6 100644
--- a/services/vr/vr_window_manager/display_view.h
+++ b/services/vr/vr_window_manager/display_view.h
@@ -29,7 +29,7 @@
 
   void OnDrawFrame(SurfaceFlingerView* surface_flinger_view, bool debug_mode);
   void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
-               const mat4& head_matrix, const vec2& size, float fade_value);
+               const mat4& head_matrix, float fade_value);
 
   void Recenter(const mat4& initial);
 
@@ -43,6 +43,7 @@
   const vec2& hit_location() const { return hit_location_in_window_coord_; }
   uint32_t id() const { return id_; }
   int touchpad_id() const { return touchpad_id_; }
+  vec2 size() const { return size_; }
 
   void set_2dmode(bool mode) { use_2dmode_ = mode; }
   void set_always_2d(bool mode) { always_2d_ = mode; }
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index 2d2a85c..43f5042 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -38,30 +38,39 @@
 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));
+  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,
-                          bool removed)
-    : display_id_(display_id), removed_(removed), layers_(std::move(layers)) {}
+                          bool removed, int32_t display_width,
+                          int32_t display_height)
+    : display_id_(display_id),
+      removed_(removed),
+      display_width_(display_width),
+      display_height_(display_height),
+      layers_(std::move(layers)) {}
 
 HwcCallback::FrameStatus HwcCallback::Frame::Finish() {
   if (status_ == FrameStatus::kUnfinished)
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index b8aa51b..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 {
@@ -81,16 +83,21 @@
 
   class Frame {
   public:
-    Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, bool removed);
+    Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, bool removed,
+          int32_t display_width, int32_t display_height);
 
     FrameStatus Finish();
     const std::vector<HwcLayer>& layers() const { return layers_; }
     uint32_t display_id() const { return display_id_; }
     bool removed() const { return removed_; }
+    int32_t display_width() const { return display_width_; }
+    int32_t display_height() const { return display_height_; }
 
   private:
     uint32_t display_id_;
     bool removed_;
+    int32_t display_width_;
+    int32_t display_height_;
     std::vector<HwcLayer> layers_;
     FrameStatus status_ = FrameStatus::kUnfinished;
   };
@@ -105,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 3aae228..850f604 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -194,8 +194,11 @@
 
   result.append("[displays]\n");
   result.appendFormat("count = %zu\n", displays_.size());
-  for (size_t i = 0; i < displays_.size(); ++i)
-    result.appendFormat(" display_id = %" PRId32 "\n", displays_[i]->id());
+  for (size_t i = 0; i < displays_.size(); ++i) {
+    result.appendFormat("  display_id = %" PRId32 "\n", displays_[i]->id());
+    result.appendFormat("    size=%fx%f\n",
+                        displays_[i]->size().x(), displays_[i]->size().y());
+  }
 
   result.append("\n");
 }
@@ -327,12 +330,9 @@
     should_recenter_ = false;
   }
 
-  size_ = vec2(surface_flinger_view_->width(), surface_flinger_view_->height());
-
   for (auto& display : displays_) {
     if (display->visible()) {
-      display->DrawEye(eye, perspective, eye_matrix, head_matrix, size_,
-                       fade_value_);
+      display->DrawEye(eye, perspective, eye_matrix, head_matrix, fade_value_);
     }
   }
 
@@ -481,9 +481,10 @@
     return;
 
   const vec2& hit_location = active_display_->hit_location();
+  const vec2 size = active_display_->size();
 
-  float x = hit_location.x() / size_.x();
-  float y = hit_location.y() / size_.y();
+  float x = hit_location.x() / size.x();
+  float y = hit_location.y() / size.y();
 
   // Device is portrait, but in landscape when in VR.
   // Rotate touch input appropriately.
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index 8548dc1..be2ae58 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -83,7 +83,6 @@
 
   bool is_touching_ = false;
   int touchpad_buttons_ = 0;
-  vec2 size_;
 
   // Used to center the scene when the shell becomes visible.
   bool should_recenter_ = true;
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index 7ecc542..aef23a1 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -1,7 +1,8 @@
 #include "surface_flinger_view.h"
 
+#include <android/dvr/IVrComposer.h>
+#include <binder/IServiceManager.h>
 #include <impl/vr_composer_view.h>
-#include <private/dvr/display_client.h>
 #include <private/dvr/native_buffer.h>
 
 #include "hwc_callback.h"
@@ -15,52 +16,23 @@
 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");
+  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;
   }
 
-  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");
-    return false;
-  }
-
-  vr_composer_view_ =
-      std::make_unique<VrComposerView>(std::make_unique<HwcCallback>(client));
-  vr_composer_view_->Initialize(GetComposerViewFromIComposer(
-      vr_hwcomposer_.get()));
-
-  int error = 0;
-  auto display_client = DisplayClient::Create(&error);
-  SystemDisplayMetrics metrics;
-
-  if (error) {
-    ALOGE("Could not connect to display service : %s(%d)", strerror(error), error);
-  } else {
-    error = display_client->GetDisplayMetrics(&metrics);
-
-    if (error) {
-      ALOGE("Could not get display metrics from display service : %s(%d)", strerror(error), error);
-    }
-  }
-
-  if (error) {
-    metrics.display_native_height = 1920;
-    metrics.display_native_width = 1080;
-    ALOGI("Setting display metrics to default : width=%d height=%d", metrics.display_native_height, metrics.display_native_width);
-  }
-
-  width_ = metrics.display_native_width;
-  height_ = metrics.display_native_height;
   return true;
 }
 
diff --git a/services/vr/vr_window_manager/surface_flinger_view.h b/services/vr/vr_window_manager/surface_flinger_view.h
index 7370299..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 {
@@ -26,9 +25,6 @@
   SurfaceFlingerView();
   ~SurfaceFlingerView();
 
-  int width() const { return width_; }
-  int height() const { return height_; }
-
   bool Initialize(HwcCallback::Client *client);
 
   bool GetTextures(const HwcCallback::Frame& layers,
@@ -37,10 +33,8 @@
                    bool skip_first_layer) const;
 
  private:
-  sp<IComposer> vr_hwcomposer_;
-  std::unique_ptr<VrComposerView> vr_composer_view_;
-  int width_ = 0;
-  int height_ = 0;
+  sp<IVrComposer> vr_composer_;
+  sp<HwcCallback> composer_callback_;
 
   SurfaceFlingerView(const SurfaceFlingerView&) = delete;
   void operator=(const SurfaceFlingerView&) = delete;
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 5574da2..3b785e6 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -183,7 +183,9 @@
         : surface(surface_),
           num_images(num_images_),
           mailbox_mode(present_mode == VK_PRESENT_MODE_MAILBOX_KHR),
-          frame_timestamps_enabled(false) {
+          frame_timestamps_enabled(false),
+          shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
+                 present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
         ANativeWindow* window = surface.window.get();
         int64_t rdur;
         native_window_get_refresh_cycle_duration(
@@ -197,6 +199,7 @@
     bool mailbox_mode;
     bool frame_timestamps_enabled;
     uint64_t refresh_duration;
+    bool shared;
 
     struct Image {
         Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
@@ -927,34 +930,10 @@
         return VK_ERROR_SURFACE_LOST_KHR;
     }
 
-    int query_value;
-    err = surface.window->query(surface.window.get(),
-                                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-                                &query_value);
-    if (err != 0 || query_value < 0) {
-        // TODO(jessehall): Improve error reporting. Can we enumerate possible
-        // errors and translate them to valid Vulkan result codes?
-        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
-              query_value);
-        return VK_ERROR_SURFACE_LOST_KHR;
-    }
-    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
-    uint32_t num_images =
-        (create_info->minImageCount - 1) + min_undequeued_buffers;
-    err = native_window_set_buffer_count(surface.window.get(), num_images);
-    if (err != 0) {
-        // TODO(jessehall): Improve error reporting. Can we enumerate possible
-        // errors and translate them to valid Vulkan result codes?
-        ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
-              strerror(-err), err);
-        return VK_ERROR_SURFACE_LOST_KHR;
-    }
-
     VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0;
     if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
         create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
         swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID;
-
         err = native_window_set_shared_buffer_mode(surface.window.get(), true);
         if (err != 0) {
             ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err);
@@ -970,28 +949,41 @@
         }
     }
 
+    int query_value;
+    err = surface.window->query(surface.window.get(),
+                                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                                &query_value);
+    if (err != 0 || query_value < 0) {
+        // TODO(jessehall): Improve error reporting. Can we enumerate possible
+        // errors and translate them to valid Vulkan result codes?
+        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
+              query_value);
+        return VK_ERROR_SURFACE_LOST_KHR;
+    }
+    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
+    uint32_t num_images =
+        (create_info->minImageCount - 1) + min_undequeued_buffers;
+
+    // Lower layer insists that we have at least two buffers. This is wasteful
+    // and we'd like to relax it in the shared case, but not all the pieces are
+    // in place for that to work yet. Note we only lie to the lower layer-- we
+    // don't want to give the app back a swapchain with extra images (which they
+    // can't actually use!).
+    err = native_window_set_buffer_count(surface.window.get(), std::max(2u, num_images));
+    if (err != 0) {
+        // TODO(jessehall): Improve error reporting. Can we enumerate possible
+        // errors and translate them to valid Vulkan result codes?
+        ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
+              strerror(-err), err);
+        return VK_ERROR_SURFACE_LOST_KHR;
+    }
+
     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;
@@ -1106,17 +1098,19 @@
     //
     // TODO(jessehall): The error path here is the same as DestroySwapchain,
     // but not the non-error path. Should refactor/unify.
-    for (uint32_t i = 0; i < num_images; i++) {
-        Swapchain::Image& img = swapchain->images[i];
-        if (img.dequeued) {
-            surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
-                                         img.dequeue_fence);
-            img.dequeue_fence = -1;
-            img.dequeued = false;
-        }
-        if (result != VK_SUCCESS) {
-            if (img.image)
-                dispatch.DestroyImage(device, img.image, nullptr);
+    if (!swapchain->shared) {
+        for (uint32_t i = 0; i < num_images; i++) {
+            Swapchain::Image& img = swapchain->images[i];
+            if (img.dequeued) {
+                surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
+                                             img.dequeue_fence);
+                img.dequeue_fence = -1;
+                img.dequeued = false;
+            }
+            if (result != VK_SUCCESS) {
+                if (img.image)
+                    dispatch.DestroyImage(device, img.image, nullptr);
+            }
         }
     }
 
@@ -1200,6 +1194,16 @@
         timeout != UINT64_MAX,
         "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
 
+    if (swapchain.shared) {
+        // In shared mode, we keep the buffer dequeued all the time, so we don't
+        // want to dequeue a buffer here. Instead, just ask the driver to ensure
+        // the semaphore and fence passed to us will be signalled.
+        *image_index = 0;
+        result = GetData(device).driver.AcquireImageANDROID(
+                device, swapchain.images[*image_index].image, -1, semaphore, vk_fence);
+        return result;
+    }
+
     ANativeWindowBuffer* buffer;
     int fence_fd;
     err = window->dequeueBuffer(window, &buffer, &fence_fd);
@@ -1420,6 +1424,7 @@
                             static_cast<int64_t>(time->desiredPresentTime));
                     }
                 }
+
                 err = window->queueBuffer(window, img.buffer.get(), fence);
                 // queueBuffer always closes fence, even on error
                 if (err != 0) {
@@ -1434,6 +1439,30 @@
                     img.dequeue_fence = -1;
                 }
                 img.dequeued = false;
+
+                // If the swapchain is in shared mode, immediately dequeue the
+                // buffer so it can be presented again without an intervening
+                // call to AcquireNextImageKHR. We expect to get the same buffer
+                // back from every call to dequeueBuffer in this mode.
+                if (swapchain.shared && swapchain_result == VK_SUCCESS) {
+                    ANativeWindowBuffer* buffer;
+                    int fence_fd;
+                    err = window->dequeueBuffer(window, &buffer, &fence_fd);
+                    if (err != 0) {
+                        ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
+                        swapchain_result = WorstPresentResult(swapchain_result,
+                            VK_ERROR_SURFACE_LOST_KHR);
+                    }
+                    else if (img.buffer != buffer) {
+                        ALOGE("got wrong image back for shared swapchain");
+                        swapchain_result = WorstPresentResult(swapchain_result,
+                            VK_ERROR_SURFACE_LOST_KHR);
+                    }
+                    else {
+                        img.dequeue_fence = fence_fd;
+                        img.dequeued = true;
+                    }
+                }
             }
             if (swapchain_result != VK_SUCCESS) {
                 ReleaseSwapchainImage(device, window, fence, img);