Merge "Add alpha channel for  the EGLConfig" into oc-dev
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/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/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/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/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index 5aa9652..f464411 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -24,81 +24,81 @@
     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;
 
     return 0;
   }
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index bee4d66..d840b6c 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -146,80 +146,80 @@
 
 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;
 };
 
 int dvrGetApi(void* api, size_t struct_size, int version);
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/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/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index 8aa2fd5..3393ade 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -81,9 +81,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() {}
 
@@ -222,7 +248,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // VrHwcClient
 
-VrHwc::VrHwc() { displays_[kDefaultDisplayId].reset(new HwcDisplay()); }
+VrHwc::VrHwc() {}
 
 VrHwc::~VrHwc() {}
 
@@ -235,6 +261,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);
   }
@@ -246,7 +280,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;
 }
@@ -308,41 +342,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
@@ -510,6 +523,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..19b220b 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -56,12 +56,18 @@
   }
 
   return client_->OnFrame(std::make_unique<Frame>(
-      std::move(hwc_frame), display_frame.display_id, display_frame.removed));
+      std::move(hwc_frame), display_frame.display_id, display_frame.removed,
+      display_frame.display_width, display_frame.display_height));
 }
 
 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..c0d965a 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -81,16 +81,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;
   };
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..c0ee1fc 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -1,7 +1,6 @@
 #include "surface_flinger_view.h"
 
 #include <impl/vr_composer_view.h>
-#include <private/dvr/display_client.h>
 #include <private/dvr/native_buffer.h>
 
 #include "hwc_callback.h"
@@ -34,33 +33,6 @@
     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..3ea2b21 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.h
+++ b/services/vr/vr_window_manager/surface_flinger_view.h
@@ -26,9 +26,6 @@
   SurfaceFlingerView();
   ~SurfaceFlingerView();
 
-  int width() const { return width_; }
-  int height() const { return height_; }
-
   bool Initialize(HwcCallback::Client *client);
 
   bool GetTextures(const HwcCallback::Frame& layers,
@@ -39,8 +36,6 @@
  private:
   sp<IComposer> vr_hwcomposer_;
   std::unique_ptr<VrComposerView> vr_composer_view_;
-  int width_ = 0;
-  int height_ = 0;
 
   SurfaceFlingerView(const SurfaceFlingerView&) = delete;
   void operator=(const SurfaceFlingerView&) = delete;