Merge "Remove old dumpstate aidl methods"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 6b2e3b7..3a0aa95 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1262,7 +1262,6 @@
 
     DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
     DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
-    DumpFile("KERNEL SYNC", "/d/sync");
 
     RunCommand("PROCESSES AND THREADS",
                {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index d936dbe..606477f 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -61,15 +61,21 @@
     return gSehandle;
 }
 
+struct AuditCallbackData {
+    const Access::CallingContext* context;
+    const std::string* tname;
+};
+
 static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
-    const Access::CallingContext* ad = reinterpret_cast<Access::CallingContext*>(data);
+    const AuditCallbackData* ad = reinterpret_cast<AuditCallbackData*>(data);
 
     if (!ad) {
         LOG(ERROR) << "No service manager audit data";
         return 0;
     }
 
-    snprintf(buf, len, "pid=%d uid=%d", ad->debugPid, ad->uid);
+    snprintf(buf, len, "pid=%d uid=%d name=%s", ad->context->debugPid, ad->context->uid,
+        ad->tname->c_str());
     return 0;
 }
 
@@ -113,13 +119,20 @@
 }
 
 bool Access::canList(const CallingContext& ctx) {
-    return actionAllowed(ctx, mThisProcessContext, "list");
+    return actionAllowed(ctx, mThisProcessContext, "list", "service_manager");
 }
 
-bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm) {
+bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
+        const std::string& tname) {
     const char* tclass = "service_manager";
 
-    return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast<void*>(const_cast<CallingContext*>((&sctx))));
+    AuditCallbackData data = {
+        .context = &sctx,
+        .tname = &tname,
+    };
+
+    return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm,
+        reinterpret_cast<void*>(&data));
 }
 
 bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
@@ -129,7 +142,7 @@
         return false;
     }
 
-    bool allowed = actionAllowed(sctx, tctx, perm);
+    bool allowed = actionAllowed(sctx, tctx, perm, name);
     freecon(tctx);
     return allowed;
 }
diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h
index 05a60d3..77c2cd4 100644
--- a/cmds/servicemanager/Access.h
+++ b/cmds/servicemanager/Access.h
@@ -45,7 +45,8 @@
     virtual bool canList(const CallingContext& ctx);
 
 private:
-    bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm);
+    bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
+            const std::string& tname);
     bool actionAllowedFromLookup(const CallingContext& sctx, const std::string& name,
             const char *perm);
 
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index c2c71e0..5f7dc25 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -52,7 +52,6 @@
         }
     }
 
-    // TODO(b/136023468): move this check to be first
     if (!mAccess->canFind(ctx, name)) {
         // returns ok and null for legacy reasons
         *outBinder = nullptr;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b230943..c6ce576 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -70,6 +70,7 @@
         "ProcessInfoService.cpp",
         "ProcessState.cpp",
         "Static.cpp",
+        "Stability.cpp",
         "Status.cpp",
         "TextOutput.cpp",
         "IpPrefix.cpp",
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index bdf0f8e..268c85e 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -124,6 +124,7 @@
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
     data.setDataPosition(0);
+    data.setTransactingBinder(this);
 
     status_t err = NO_ERROR;
     switch (code) {
@@ -135,8 +136,10 @@
             break;
     }
 
+    // In case this is being transacted on in the same process.
     if (reply != nullptr) {
         reply->setDataPosition(0);
+        reply->setTransactingBinder(this);
     }
 
     return err;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 5ceb218..57440d5 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -216,6 +216,11 @@
         status_t status = IPCThreadState::self()->transact(
             mHandle, code, data, reply, flags);
         if (status == DEAD_OBJECT) mAlive = 0;
+
+        if (reply != nullptr) {
+            reply->setTransactingBinder(this);
+        }
+
         return status;
     }
 
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index cfb86f0..7c45c77 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -465,7 +465,7 @@
 
 void IPCThreadState::flushCommands()
 {
-    if (mProcess->mDriverFD <= 0)
+    if (mProcess->mDriverFD < 0)
         return;
     talkWithDriver(false);
     // The flush could have caused post-write refcount decrements to have
@@ -618,7 +618,7 @@
 
 int IPCThreadState::setupPolling(int* fd)
 {
-    if (mProcess->mDriverFD <= 0) {
+    if (mProcess->mDriverFD < 0) {
         return -EBADF;
     }
 
@@ -924,7 +924,7 @@
 
 status_t IPCThreadState::talkWithDriver(bool doReceive)
 {
-    if (mProcess->mDriverFD <= 0) {
+    if (mProcess->mDriverFD < 0) {
         return -EBADF;
     }
 
@@ -982,7 +982,7 @@
 #else
         err = INVALID_OPERATION;
 #endif
-        if (mProcess->mDriverFD <= 0) {
+        if (mProcess->mDriverFD < 0) {
             err = -EBADF;
         }
         IF_LOG_COMMANDS() {
@@ -1301,7 +1301,7 @@
         if (self) {
                 self->flushCommands();
 #if defined(__ANDROID__)
-        if (self->mProcess->mDriverFD > 0) {
+        if (self->mProcess->mDriverFD >= 0) {
             ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
         }
 #endif
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 6bd97d58..4487778 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -77,6 +77,9 @@
 
 namespace android {
 
+// many things compile this into prebuilts on the stack
+static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120);
+
 static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER;
 static size_t gParcelGlobalAllocSize = 0;
 static size_t gParcelGlobalAllocCount = 0;
@@ -164,14 +167,36 @@
     ALOGE("Invalid object type 0x%08x", obj.hdr.type);
 }
 
-inline static status_t finish_flatten_binder(
-    const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
+status_t Parcel::finishFlattenBinder(
+    const sp<IBinder>& binder, const flat_binder_object& flat)
 {
-    return out->writeObject(flat, false);
+    internal::Stability::tryMarkCompilationUnit(binder.get());
+
+    status_t status = writeObject(flat, false);
+    if (status != OK) return status;
+
+    return writeInt32(internal::Stability::get(binder.get()));
 }
 
-static status_t flatten_binder(const sp<ProcessState>& /*proc*/,
-    const sp<IBinder>& binder, Parcel* out)
+status_t Parcel::finishUnflattenBinder(
+    const sp<IBinder>& binder, sp<IBinder>* out) const
+{
+    int32_t stability;
+    status_t status = readInt32(&stability);
+    if (status != OK) return status;
+
+    if (binder != nullptr && !internal::Stability::check(stability, mRequiredStability)) {
+        return BAD_TYPE;
+    }
+
+    status = internal::Stability::set(binder.get(), stability, true /*log*/);
+    if (status != OK) return status;
+
+    *out = binder;
+    return OK;
+}
+
+status_t Parcel::flattenBinder(const sp<IBinder>& binder)
 {
     flat_binder_object obj;
 
@@ -209,30 +234,24 @@
         obj.cookie = 0;
     }
 
-    return finish_flatten_binder(binder, obj, out);
+    return finishFlattenBinder(binder, obj);
 }
 
-inline static status_t finish_unflatten_binder(
-    BpBinder* /*proxy*/, const flat_binder_object& /*flat*/,
-    const Parcel& /*in*/)
+status_t Parcel::unflattenBinder(sp<IBinder>* out) const
 {
-    return NO_ERROR;
-}
-
-static status_t unflatten_binder(const sp<ProcessState>& proc,
-    const Parcel& in, sp<IBinder>* out)
-{
-    const flat_binder_object* flat = in.readObject(false);
+    const flat_binder_object* flat = readObject(false);
 
     if (flat) {
         switch (flat->hdr.type) {
-            case BINDER_TYPE_BINDER:
-                *out = reinterpret_cast<IBinder*>(flat->cookie);
-                return finish_unflatten_binder(nullptr, *flat, in);
-            case BINDER_TYPE_HANDLE:
-                *out = proc->getStrongProxyForHandle(flat->handle);
-                return finish_unflatten_binder(
-                    static_cast<BpBinder*>(out->get()), *flat, in);
+            case BINDER_TYPE_BINDER: {
+                sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie);
+                return finishUnflattenBinder(binder, out);
+            }
+            case BINDER_TYPE_HANDLE: {
+                sp<IBinder> binder =
+                    ProcessState::self()->getStrongProxyForHandle(flat->handle);
+                return finishUnflattenBinder(binder, out);
+            }
         }
     }
     return BAD_TYPE;
@@ -337,6 +356,10 @@
     return NO_ERROR;
 }
 
+void Parcel::setTransactingBinder(const sp<IBinder>& binder) const {
+    mRequiredStability = internal::Stability::get(binder.get());
+}
+
 status_t Parcel::setData(const uint8_t* buffer, size_t len)
 {
     if (len > INT32_MAX) {
@@ -1032,7 +1055,7 @@
 
 status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
 {
-    return flatten_binder(ProcessState::self(), val, this);
+    return flattenBinder(val);
 }
 
 status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
@@ -1978,7 +2001,7 @@
 
 status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
 {
-    return unflatten_binder(ProcessState::self(), *this, val);
+    return unflattenBinder(val);
 }
 
 sp<IBinder> Parcel::readStrongBinder() const
@@ -2682,9 +2705,10 @@
     mObjectsCapacity = 0;
     mNextObjectHint = 0;
     mObjectsSorted = false;
+    mAllowFds = true;
     mHasFds = false;
     mFdsKnown = true;
-    mAllowFds = true;
+    mRequiredStability = internal::Stability::UNDECLARED;
     mOwner = nullptr;
     mOpenAshmemSize = 0;
     mWorkSourceRequestHeaderPosition = 0;
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
new file mode 100644
index 0000000..0a10a1d
--- /dev/null
+++ b/libs/binder/Stability.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2019 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/Stability.h>
+
+namespace android {
+namespace internal {
+
+void Stability::markCompilationUnit(IBinder* binder) {
+    status_t result = set(binder, kLocalStability, true /*log*/);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::markVintf(IBinder* binder) {
+    status_t result = set(binder, Level::VINTF, true /*log*/);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::debugLogStability(const std::string& tag, const sp<IBinder>& binder) {
+    ALOGE("%s: stability is %s", tag.c_str(), stabilityString(get(binder.get())).c_str());
+}
+
+void Stability::tryMarkCompilationUnit(IBinder* binder) {
+    (void) set(binder, kLocalStability, false /*log*/);
+}
+
+status_t Stability::set(IBinder* binder, int32_t stability, bool log) {
+    Level currentStability = get(binder);
+
+    // null binder is always written w/ 'UNDECLARED' stability
+    if (binder == nullptr) {
+        if (stability == UNDECLARED) {
+            return OK;
+        } else {
+            if (log) {
+                ALOGE("Null binder written with stability %s.",
+                    stabilityString(stability).c_str());
+            }
+            return BAD_TYPE;
+        }
+    }
+
+    if (!isDeclaredStability(stability)) {
+        if (log) {
+            ALOGE("Can only set known stability, not %d.", stability);
+        }
+        return BAD_TYPE;
+    }
+
+    if (currentStability != Level::UNDECLARED && currentStability != stability) {
+        if (log) {
+            ALOGE("Interface being set with %s but it is already marked as %s.",
+                stabilityString(stability).c_str(), stabilityString(currentStability).c_str());
+        }
+        return BAD_TYPE;
+    }
+
+    if (currentStability == stability) return OK;
+
+    binder->attachObject(
+        reinterpret_cast<void*>(&Stability::get),
+        reinterpret_cast<void*>(stability),
+        nullptr /*cleanupCookie*/,
+        nullptr /*cleanup function*/);
+
+    return OK;
+}
+
+Stability::Level Stability::get(IBinder* binder) {
+    if (binder == nullptr) return UNDECLARED;
+
+    return static_cast<Level>(reinterpret_cast<intptr_t>(
+        binder->findObject(reinterpret_cast<void*>(&Stability::get))));
+}
+
+bool Stability::check(int32_t provided, Level required) {
+    bool stable = (provided & required) == required;
+
+    if (!isDeclaredStability(provided) && provided != UNDECLARED) {
+        ALOGE("Unknown stability when checking interface stability %d.", provided);
+
+        stable = false;
+    }
+
+    if (!stable) {
+        ALOGE("Interface with %s cannot accept interface with %s.",
+            stabilityString(required).c_str(),
+            stabilityString(provided).c_str());
+    }
+
+    return stable;
+}
+
+bool Stability::isDeclaredStability(int32_t stability) {
+    return stability == VENDOR || stability == SYSTEM || stability == VINTF;
+}
+
+std::string Stability::stabilityString(int32_t stability) {
+    switch (stability) {
+        case Level::UNDECLARED: return "undeclared stability";
+        case Level::VENDOR: return "vendor stability";
+        case Level::SYSTEM: return "system stability";
+        case Level::VINTF: return "vintf stability";
+    }
+    return "unknown stability " + std::to_string(stability);
+}
+
+}  // namespace internal
+}  // namespace stability
\ No newline at end of file
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 01e57d3..136bdb0 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -11,6 +11,9 @@
     },
     {
       "name": "binderLibTest"
+    },
+    {
+      "name": "binderStabilityTest"
     }
   ]
 }
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index cf3ef84..1537e69 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -54,9 +54,9 @@
     virtual void        attachObject(   const void* objectID,
                                         void* object,
                                         void* cleanupCookie,
-                                        object_cleanup_func func);
-    virtual void*       findObject(const void* objectID) const;
-    virtual void        detachObject(const void* objectID);
+                                        object_cleanup_func func) final;
+    virtual void*       findObject(const void* objectID) const final;
+    virtual void        detachObject(const void* objectID) final;
 
     virtual BBinder*    localBinder();
 
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index b3a1d0b..e71541b 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -61,9 +61,9 @@
     virtual void        attachObject(   const void* objectID,
                                         void* object,
                                         void* cleanupCookie,
-                                        object_cleanup_func func);
-    virtual void*       findObject(const void* objectID) const;
-    virtual void        detachObject(const void* objectID);
+                                        object_cleanup_func func) final;
+    virtual void*       findObject(const void* objectID) const final;
+    virtual void        detachObject(const void* objectID) final;
 
     virtual BpBinder*   remoteBinder();
 
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index aeea1a2..30786fa 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -71,13 +71,6 @@
      */
     // NOLINTNEXTLINE(google-default-arguments)
     virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
-
-    enum {
-        GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
-        CHECK_SERVICE_TRANSACTION,
-        ADD_SERVICE_TRANSACTION,
-        LIST_SERVICES_TRANSACTION,
-    };
 };
 
 sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 28ab4d9..698fc07 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -33,6 +33,7 @@
 
 #include <binder/IInterface.h>
 #include <binder/Parcelable.h>
+#include <binder/Stability.h>
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -67,7 +68,9 @@
     status_t            setDataSize(size_t size);
     void                setDataPosition(size_t pos) const;
     status_t            setDataCapacity(size_t size);
-    
+
+    void                setTransactingBinder(const sp<IBinder>& binder) const;
+
     status_t            setData(const uint8_t* buffer, size_t len);
 
     status_t            appendFrom(const Parcel *parcel,
@@ -419,7 +422,13 @@
     void                scanForFds() const;
     status_t            validateReadData(size_t len) const;
     void                updateWorkSourceRequestHeaderPosition() const;
-                        
+
+    status_t            finishFlattenBinder(const sp<IBinder>& binder,
+                                            const flat_binder_object& flat);
+    status_t            finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const;
+    status_t            flattenBinder(const sp<IBinder>& binder);
+    status_t            unflattenBinder(sp<IBinder>* out) const;
+
     template<class T>
     status_t            readAligned(T *pArg) const;
 
@@ -466,13 +475,15 @@
     size_t              mObjectsCapacity;
     mutable size_t      mNextObjectHint;
     mutable bool        mObjectsSorted;
+    bool                mAllowFds;
 
     mutable bool        mRequestHeaderPresent;
     mutable size_t      mWorkSourceRequestHeaderPosition;
 
     mutable bool        mFdsKnown;
     mutable bool        mHasFds;
-    bool                mAllowFds;
+
+    mutable internal::Stability::Level mRequiredStability;
 
     release_func        mOwner;
     void*               mOwnerCookie;
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
new file mode 100644
index 0000000..9d98c7f
--- /dev/null
+++ b/libs/binder/include/binder/Stability.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 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/IBinder.h>
+#include <string>
+
+namespace android {
+namespace internal {
+
+// WARNING: These APIs are only ever expected to be called by auto-generated code.
+//     Instead of calling them, you should set the stability of a .aidl interface
+class Stability final {
+public:
+    // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
+    // change or modify the stability class of the interface you are using.
+    // This must be called as soon as the binder in question is constructed. No thread safety
+    // is provided.
+    // E.g. stability is according to libbinder compilation unit
+    static void markCompilationUnit(IBinder* binder);
+    // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
+    // change or modify the stability class of the interface you are using.
+    // This must be called as soon as the binder in question is constructed. No thread safety
+    // is provided.
+    // E.g. stability is according to libbinder_ndk or Java SDK AND the interface
+    //     expressed here is guaranteed to be stable for multiple years (Stable AIDL)
+    static void markVintf(IBinder* binder);
+
+    // WARNING: for debugging only
+    static void debugLogStability(const std::string& tag, const sp<IBinder>& binder);
+
+private:
+    // Parcel needs to store stability level since this is more efficient than storing and looking
+    // up the efficiency level of a binder object. So, we expose the underlying type.
+    friend ::android::Parcel;
+
+    static void tryMarkCompilationUnit(IBinder* binder);
+
+    enum Level : int16_t {
+        UNDECLARED = 0,
+
+        VENDOR = 0b000011,
+        SYSTEM = 0b001100,
+        VINTF = 0b111111,
+    };
+
+#ifdef __ANDROID_VNDK__
+    static constexpr Level kLocalStability = Level::VENDOR;
+#else
+    static constexpr Level kLocalStability = Level::SYSTEM;
+#endif
+
+    // applies stability to binder if stability level is known
+    __attribute__((warn_unused_result))
+    static status_t set(IBinder* binder, int32_t stability, bool log);
+
+    static Level get(IBinder* binder);
+
+    static bool check(int32_t provided, Level required);
+
+    static bool isDeclaredStability(int32_t stability);
+    static std::string stabilityString(int32_t stability);
+
+    Stability();
+};
+
+}  // namespace internal
+}  // namespace android
diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh
deleted file mode 100755
index 3529b72..0000000
--- a/libs/binder/ndk/scripts/init_map.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env bash
-
-# Simple helper for ease of development until this API is frozen.
-
-echo "LIBBINDER_NDK { # introduced=29"
-echo "  global:"
-{
-    grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder.h;
-    grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder_jni.h;
-    grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h;
-    grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h;
-} | sort | uniq | awk '{ print "    " $0 ";"; }'
-{
-    grep -oP "AServiceManager_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_manager.h;
-    grep -oP "ABinderProcess_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_process.h;
-} | sort | uniq | awk '{ print "    " $0 "; # apex"; }'
-echo "  local:"
-echo "    *;"
-echo "};"
diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh
index 9a4577f..1eba892 100755
--- a/libs/binder/ndk/update.sh
+++ b/libs/binder/ndk/update.sh
@@ -20,4 +20,3 @@
 # This script makes sure that the source code is in sync with the various scripts
 ./scripts/gen_parcel_helper.py
 ./scripts/format.sh
-./scripts/init_map.sh > libbinder_ndk.map.txt
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 44a691d..05db81e 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -137,3 +137,18 @@
     ],
     test_suites: ["device-tests"],
 }
+
+cc_test {
+    name: "binderStabilityTest",
+    defaults: ["binder_test_defaults"],
+    srcs: [
+        "binderStabilityTest.cpp",
+        "IBinderStabilityTest.aidl",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/libs/binder/tests/IBinderStabilityTest.aidl b/libs/binder/tests/IBinderStabilityTest.aidl
new file mode 100644
index 0000000..7540ec9
--- /dev/null
+++ b/libs/binder/tests/IBinderStabilityTest.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+// THIS IS ONLY FOR TESTING!
+interface IBinderStabilityTest {
+    // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+    // THIS IS ONLY FOR TESTING!
+    void sendBinder(IBinder binder);
+
+    // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+    // THIS IS ONLY FOR TESTING!
+    IBinder returnNoStabilityBinder();
+
+    // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+    // THIS IS ONLY FOR TESTING!
+    IBinder returnLocalStabilityBinder();
+
+    // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+    // THIS IS ONLY FOR TESTING!
+    IBinder returnVintfStabilityBinder();
+}
+// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+// THIS IS ONLY FOR TESTING!
+// Construct and return a binder with a specific stability
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
new file mode 100644
index 0000000..0218b94
--- /dev/null
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2019 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 <android/os/IServiceManager.h>
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Stability.h>
+#include <gtest/gtest.h>
+
+#include <sys/prctl.h>
+
+#include "BnBinderStabilityTest.h"
+#include "BpBinderStabilityTest.h"
+
+using namespace android;
+using android::binder::Status;
+using android::os::IServiceManager;
+
+const String16 kNoStabilityServer = String16("binder_stability_test_service_low");
+const String16 kCompilationUnitServer = String16("binder_stability_test_service_compl");
+const String16 kVintfServer = String16("binder_stability_test_service_vintf");
+
+sp<IBinder> getCompilationUnitStability() {
+    sp<IBinder> binder = new BBinder();
+    // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
+    // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
+    internal::Stability::markCompilationUnit(binder.get()); // <- BAD, NO! DO NOT COPY
+    return binder;
+}
+
+sp<IBinder> getVintfStability() {
+    sp<IBinder> binder = new BBinder();
+    // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
+    // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
+    internal::Stability::markVintf(binder.get()); // <- BAD, NO! DO NOT COPY
+    return binder;
+}
+
+// NO! NO! NO! Do not even think of doing something like this!
+// This is for testing! If a class like this was actually used in production,
+// it would ruin everything!
+class BadStabilityTester : public BnBinderStabilityTest {
+public:
+    Status sendBinder(const sp<IBinder>& /*binder*/) override {
+        return Status::ok();
+    }
+    Status returnNoStabilityBinder(sp<IBinder>* _aidl_return) override {
+        *_aidl_return = new BBinder();
+        return Status::ok();
+    }
+    Status returnLocalStabilityBinder(sp<IBinder>* _aidl_return) override {
+        *_aidl_return = getCompilationUnitStability();
+        return Status::ok();
+    }
+    Status returnVintfStabilityBinder(sp<IBinder>* _aidl_return) override {
+        *_aidl_return = getVintfStability();
+        return Status::ok();
+    }
+
+    static sp<IBinderStabilityTest> getNoStabilityServer() {
+        sp<IBinder> remote = new BadStabilityTester;
+        return new BpBinderStabilityTest(remote);
+    }
+    static sp<IBinderStabilityTest> getCompilationUnitStabilityServer() {
+        sp<IBinder> remote = new BadStabilityTester;
+        internal::Stability::markCompilationUnit(remote.get());
+        return new BpBinderStabilityTest(remote);
+    }
+    static sp<IBinderStabilityTest> getVintfStabilityServer() {
+        sp<IBinder> remote = new BadStabilityTester;
+        internal::Stability::markVintf(remote.get()); // <- BAD, NO! DO NOT COPY
+        return new BpBinderStabilityTest(remote);
+    }
+};
+
+void checkLocalStabilityBinder(const sp<IBinderStabilityTest>& complServer) {
+    // this binder should automatically be set to local stability
+    EXPECT_TRUE(complServer->sendBinder(new BBinder()).isOk());
+    EXPECT_TRUE(complServer->sendBinder(getCompilationUnitStability()).isOk());
+    EXPECT_TRUE(complServer->sendBinder(getVintfStability()).isOk());
+
+    sp<IBinder> out;
+    // should automatically be set to local stability
+    EXPECT_TRUE(complServer->returnNoStabilityBinder(&out).isOk());
+    EXPECT_NE(nullptr, out.get());
+
+    EXPECT_TRUE(complServer->returnLocalStabilityBinder(&out).isOk());
+    EXPECT_NE(nullptr, out.get());
+
+    EXPECT_TRUE(complServer->returnVintfStabilityBinder(&out).isOk());
+    EXPECT_NE(nullptr, out.get());
+}
+
+void checkHighStabilityServer(const sp<IBinderStabilityTest>& highStability) {
+    EXPECT_FALSE(highStability->sendBinder(new BBinder()).isOk());
+    EXPECT_FALSE(highStability->sendBinder(getCompilationUnitStability()).isOk());
+    EXPECT_TRUE(highStability->sendBinder(getVintfStability()).isOk());
+
+    sp<IBinder> out;
+    EXPECT_FALSE(highStability->returnNoStabilityBinder(&out).isOk());
+    EXPECT_EQ(nullptr, out.get());
+
+    EXPECT_FALSE(highStability->returnLocalStabilityBinder(&out).isOk());
+    EXPECT_EQ(nullptr, out.get());
+
+    EXPECT_TRUE(highStability->returnVintfStabilityBinder(&out).isOk());
+    EXPECT_NE(nullptr, out.get());
+}
+
+TEST(BinderStability, LocalNoStabilityServer) {
+    // in practice, a low stability server is probably one that hasn't been rebuilt
+    // or was written by hand.
+    auto server = BadStabilityTester::getNoStabilityServer();
+    ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder());
+
+    // it should be considered to have local stability
+    checkLocalStabilityBinder(server);
+}
+
+TEST(BinderStability, LocalLowStabilityServer) {
+    auto server = BadStabilityTester::getCompilationUnitStabilityServer();
+    ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder());
+    checkLocalStabilityBinder(server);
+}
+
+TEST(BinderStability, LocalHighStabilityServer) {
+    auto server = BadStabilityTester::getVintfStabilityServer();
+    ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder());
+    checkHighStabilityServer(server);
+}
+
+TEST(BinderStability, RemoteNoStabilityServer) {
+    sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kNoStabilityServer);
+    auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+    ASSERT_NE(nullptr, remoteServer.get());
+    ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+    // it should be considered to have local stability
+    checkLocalStabilityBinder(remoteServer);
+}
+
+TEST(BinderStability, RemoteLowStabilityServer) {
+    sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kCompilationUnitServer);
+    auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+    ASSERT_NE(nullptr, remoteServer.get());
+    ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+    checkLocalStabilityBinder(remoteServer);
+}
+
+TEST(BinderStability, RemoteVintfServer) {
+    sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kVintfServer);
+    auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+    ASSERT_NE(nullptr, remoteServer.get());
+    ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+    checkHighStabilityServer(remoteServer);
+}
+
+class MarksStabilityInConstructor : public BBinder {
+public:
+    static bool gDestructed;
+
+    MarksStabilityInConstructor() {
+        internal::Stability::markCompilationUnit(this);
+    }
+    ~MarksStabilityInConstructor() {
+        gDestructed = true;
+    }
+};
+bool MarksStabilityInConstructor::gDestructed = false;
+
+TEST(BinderStability, MarkingObjectNoDestructTest) {
+    ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+    // best practice is to put this directly in an sp, but for this test, we
+    // want to explicitly check what happens before that happens
+    MarksStabilityInConstructor* binder = new MarksStabilityInConstructor();
+    ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+    sp<MarksStabilityInConstructor> binderSp = binder;
+    ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+    binderSp = nullptr;
+    ASSERT_TRUE(MarksStabilityInConstructor::gDestructed);
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (fork() == 0) {
+        // child process
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+        sp<IBinder> noStability = new BadStabilityTester;
+        android::defaultServiceManager()->addService(kNoStabilityServer, noStability);
+
+        sp<IBinder> compil = new BadStabilityTester;
+        internal::Stability::markCompilationUnit(compil.get());
+        android::defaultServiceManager()->addService(kCompilationUnitServer, compil);
+
+        sp<IBinder> vintf = new BadStabilityTester;
+        internal::Stability::markVintf(vintf.get());
+        android::defaultServiceManager()->addService(kVintfServer, vintf);
+
+        IPCThreadState::self()->joinThreadPool(true);
+        exit(1);  // should not reach
+    }
+
+    // This is not racey. Just giving these services some time to register before we call
+    // getService which sleeps for much longer...
+    usleep(10000);
+
+    return RUN_ALL_TESTS();
+}
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 56521bf..f11cf62 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -32,5 +32,9 @@
         "libutils",
     ],
 
+    header_libs: [
+        "libnativeloader-dummy-headers",
+    ],
+
     export_include_dirs: ["include"],
 }
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 3e29e88..30f5f73 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -32,6 +32,7 @@
 #include <cutils/properties.h>
 #include <graphicsenv/IGpuService.h>
 #include <log/log.h>
+#include <nativeloader/dlext_namespaces.h>
 #include <sys/prctl.h>
 #include <utils/Trace.h>
 
@@ -39,22 +40,6 @@
 #include <string>
 #include <thread>
 
-// TODO(b/37049319) Get this from a header once one exists
-extern "C" {
-android_namespace_t* android_get_exported_namespace(const char*);
-android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
-                                              const char* default_library_path, uint64_t type,
-                                              const char* permitted_when_isolated_path,
-                                              android_namespace_t* parent);
-bool android_link_namespaces(android_namespace_t* from, android_namespace_t* to,
-                             const char* shared_libs_sonames);
-
-enum {
-    ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
-    ANDROID_NAMESPACE_TYPE_SHARED = 2,
-};
-}
-
 // TODO(ianelliott@): Get the following from an ANGLE header:
 #define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting
 // Version-2 API:
@@ -213,7 +198,8 @@
         case GpuStatsInfo::Driver::GL:
         case GpuStatsInfo::Driver::GL_UPDATED:
         case GpuStatsInfo::Driver::ANGLE: {
-            if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE) {
+            if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE ||
+                mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::GL) {
                 mGpuStats.glDriverToLoad = driver;
                 break;
             }
@@ -225,7 +211,8 @@
         }
         case GpuStatsInfo::Driver::VULKAN:
         case GpuStatsInfo::Driver::VULKAN_UPDATED: {
-            if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE) {
+            if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE ||
+                mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::VULKAN) {
                 mGpuStats.vkDriverToLoad = driver;
                 break;
             }
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 36211ca..cc252d6 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -26,6 +26,7 @@
         "libgui",
         "liblog",
         "libnativewindow",
+        "libprocessgroup",
         "libsync",
         "libui",
         "libutils",
@@ -51,6 +52,7 @@
         "gl/GLExtensions.cpp",
         "gl/GLFramebuffer.cpp",
         "gl/GLImage.cpp",
+        "gl/ImageManager.cpp",
         "gl/Program.cpp",
         "gl/ProgramCache.cpp",
     ],
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 8bfd3dd..dd4c55d 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -19,9 +19,8 @@
 #define LOG_TAG "RenderEngine"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include "GLESRenderEngine.h"
-
-#include <math.h>
+#include <sched.h>
+#include <cmath>
 #include <fstream>
 #include <sstream>
 #include <unordered_set>
@@ -43,6 +42,7 @@
 #include <ui/Region.h>
 #include <utils/KeyedVector.h>
 #include <utils/Trace.h>
+#include "GLESRenderEngine.h"
 #include "GLExtensions.h"
 #include "GLFramebuffer.h"
 #include "GLImage.h"
@@ -423,10 +423,13 @@
         mTraceGpuCompletion = true;
         mFlushTracer = std::make_unique<FlushTracer>(this);
     }
+    mImageManager = std::make_unique<ImageManager>(this);
     mDrawingBuffer = createFramebuffer();
 }
 
 GLESRenderEngine::~GLESRenderEngine() {
+    // Destroy the image manager first.
+    mImageManager = nullptr;
     std::lock_guard<std::mutex> lock(mRenderingMutex);
     unbindFrameBuffer(mDrawingBuffer.get());
     mDrawingBuffer = nullptr;
@@ -615,19 +618,41 @@
 status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
                                                      const sp<GraphicBuffer>& buffer,
                                                      const sp<Fence>& bufferFence) {
-    ATRACE_CALL();
-    status_t cacheResult = cacheExternalTextureBuffer(buffer);
-
-    if (cacheResult != NO_ERROR) {
-        return cacheResult;
+    if (buffer == nullptr) {
+        return BAD_VALUE;
     }
 
+    ATRACE_CALL();
+
+    bool found = false;
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+        auto cachedImage = mImageCache.find(buffer->getId());
+        found = (cachedImage != mImageCache.end());
+    }
+
+    // If we couldn't find the image in the cache at this time, then either
+    // SurfaceFlinger messed up registering the buffer ahead of time or we got
+    // backed up creating other EGLImages.
+    if (!found) {
+        status_t cacheResult = mImageManager->cache(buffer);
+        if (cacheResult != NO_ERROR) {
+            return cacheResult;
+        }
+    }
+
+    // Whether or not we needed to cache, re-check mImageCache to make sure that
+    // there's an EGLImage. The current threading model guarantees that we don't
+    // destroy a cached image until it's really not needed anymore (i.e. this
+    // function should not be called), so the only possibility is that something
+    // terrible went wrong and we should just bind something and move on.
     {
         std::lock_guard<std::mutex> lock(mRenderingMutex);
         auto cachedImage = mImageCache.find(buffer->getId());
 
         if (cachedImage == mImageCache.end()) {
             // We failed creating the image if we got here, so bail out.
+            ALOGE("Failed to create an EGLImage when rendering");
             bindExternalTextureImage(texName, *createImage());
             return NO_INIT;
         }
@@ -659,7 +684,18 @@
     return NO_ERROR;
 }
 
-status_t GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+void GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+    mImageManager->cacheAsync(buffer, nullptr);
+}
+
+std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::cacheExternalTextureBufferForTesting(
+        const sp<GraphicBuffer>& buffer) {
+    auto barrier = std::make_shared<ImageManager::Barrier>();
+    mImageManager->cacheAsync(buffer, barrier);
+    return barrier;
+}
+
+status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer) {
     if (buffer == nullptr) {
         return BAD_VALUE;
     }
@@ -699,12 +735,30 @@
 }
 
 void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    const auto& cachedImage = mImageCache.find(bufferId);
-    if (cachedImage != mImageCache.end()) {
-        ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
-        mImageCache.erase(bufferId);
-        return;
+    mImageManager->releaseAsync(bufferId, nullptr);
+}
+
+std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::unbindExternalTextureBufferForTesting(
+        uint64_t bufferId) {
+    auto barrier = std::make_shared<ImageManager::Barrier>();
+    mImageManager->releaseAsync(bufferId, barrier);
+    return barrier;
+}
+
+void GLESRenderEngine::unbindExternalTextureBufferInternal(uint64_t bufferId) {
+    std::unique_ptr<Image> image;
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+        const auto& cachedImage = mImageCache.find(bufferId);
+
+        if (cachedImage != mImageCache.end()) {
+            ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
+            // Move the buffer out of cache first, so that we can destroy
+            // without holding the cache's lock.
+            image = std::move(cachedImage->second);
+            mImageCache.erase(bufferId);
+            return;
+        }
     }
     ALOGV("Failed to find image for buffer: %" PRIu64, bufferId);
 }
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index c8b45d2..501b044 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -17,9 +17,7 @@
 #ifndef SF_GLESRENDERENGINE_H_
 #define SF_GLESRENDERENGINE_H_
 
-#include <android-base/thread_annotations.h>
 #include <stdint.h>
-#include <sys/types.h>
 #include <condition_variable>
 #include <deque>
 #include <mutex>
@@ -30,8 +28,11 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
+#include <android-base/thread_annotations.h>
 #include <renderengine/RenderEngine.h>
 #include <renderengine/private/Description.h>
+#include <sys/types.h>
+#include "ImageManager.h"
 
 #define EGL_NO_CONFIG ((EGLConfig)0)
 
@@ -63,7 +64,7 @@
     void bindExternalTextureImage(uint32_t texName, const Image& image) override;
     status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
                                        const sp<Fence>& fence) EXCLUDES(mRenderingMutex);
-    status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
+    void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
     void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
     status_t bindFrameBuffer(Framebuffer* framebuffer) override;
     void unbindFrameBuffer(Framebuffer* framebuffer) override;
@@ -87,6 +88,11 @@
     // Returns true iff mFramebufferImageCache contains an image keyed by bufferId
     bool isFramebufferImageCachedForTesting(uint64_t bufferId)
             EXCLUDES(mFramebufferImageCacheMutex);
+    // These are wrappers around public methods above, but exposing Barrier
+    // objects so that tests can block.
+    std::shared_ptr<ImageManager::Barrier> cacheExternalTextureBufferForTesting(
+            const sp<GraphicBuffer>& buffer);
+    std::shared_ptr<ImageManager::Barrier> unbindExternalTextureBufferForTesting(uint64_t bufferId);
 
 protected:
     Framebuffer* getFramebufferForDrawing() override;
@@ -116,6 +122,9 @@
     void setScissor(const Rect& region);
     void disableScissor();
     bool waitSync(EGLSyncKHR sync, EGLint flags);
+    status_t cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer)
+            EXCLUDES(mRenderingMutex);
+    void unbindExternalTextureBufferInternal(uint64_t bufferId) EXCLUDES(mRenderingMutex);
 
     // A data space is considered HDR data space if it has BT2020 color space
     // with PQ or HLG transfer function.
@@ -241,7 +250,9 @@
         bool mRunning = true;
     };
     friend class FlushTracer;
+    friend class ImageManager;
     std::unique_ptr<FlushTracer> mFlushTracer;
+    std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this);
 };
 
 } // namespace gl
diff --git a/libs/renderengine/gl/ImageManager.cpp b/libs/renderengine/gl/ImageManager.cpp
new file mode 100644
index 0000000..5af0e4f
--- /dev/null
+++ b/libs/renderengine/gl/ImageManager.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <pthread.h>
+
+#include <processgroup/sched_policy.h>
+#include <utils/Trace.h>
+#include "GLESRenderEngine.h"
+#include "ImageManager.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) {
+    pthread_setname_np(mThread.native_handle(), "ImageManager");
+    // Use SCHED_FIFO to minimize jitter
+    struct sched_param param = {0};
+    param.sched_priority = 2;
+    if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO for ImageManager");
+    }
+}
+
+ImageManager::~ImageManager() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mRunning = false;
+    }
+    mCondition.notify_all();
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void ImageManager::cacheAsync(const sp<GraphicBuffer>& buffer,
+                              const std::shared_ptr<Barrier>& barrier) {
+    if (buffer == nullptr) {
+        {
+            std::lock_guard<std::mutex> lock(barrier->mutex);
+            barrier->isOpen = true;
+            barrier->result = BAD_VALUE;
+        }
+        barrier->condition.notify_one();
+        return;
+    }
+    ATRACE_CALL();
+    QueueEntry entry = {QueueEntry::Operation::Insert, buffer, buffer->getId(), barrier};
+    queueOperation(std::move(entry));
+}
+
+status_t ImageManager::cache(const sp<GraphicBuffer>& buffer) {
+    ATRACE_CALL();
+    auto barrier = std::make_shared<Barrier>();
+    cacheAsync(buffer, barrier);
+    std::lock_guard<std::mutex> lock(barrier->mutex);
+    barrier->condition.wait(barrier->mutex,
+                            [&]() REQUIRES(barrier->mutex) { return barrier->isOpen; });
+    return barrier->result;
+}
+
+void ImageManager::releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) {
+    ATRACE_CALL();
+    QueueEntry entry = {QueueEntry::Operation::Delete, nullptr, bufferId, barrier};
+    queueOperation(std::move(entry));
+}
+
+void ImageManager::queueOperation(const QueueEntry&& entry) {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mQueue.emplace(entry);
+        ATRACE_INT("ImageManagerQueueDepth", mQueue.size());
+    }
+    mCondition.notify_one();
+}
+
+void ImageManager::threadMain() {
+    set_sched_policy(0, SP_FOREGROUND);
+    bool run;
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        run = mRunning;
+    }
+    while (run) {
+        QueueEntry entry;
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mCondition.wait(mMutex,
+                            [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; });
+            run = mRunning;
+
+            if (!mRunning) {
+                // if mRunning is false, then ImageManager is being destroyed, so
+                // bail out now.
+                break;
+            }
+
+            entry = mQueue.front();
+            mQueue.pop();
+            ATRACE_INT("ImageManagerQueueDepth", mQueue.size());
+        }
+
+        status_t result = NO_ERROR;
+        switch (entry.op) {
+            case QueueEntry::Operation::Delete:
+                mEngine->unbindExternalTextureBufferInternal(entry.bufferId);
+                break;
+            case QueueEntry::Operation::Insert:
+                result = mEngine->cacheExternalTextureBufferInternal(entry.buffer);
+                break;
+        }
+        if (entry.barrier != nullptr) {
+            {
+                std::lock_guard<std::mutex> entryLock(entry.barrier->mutex);
+                entry.barrier->result = result;
+                entry.barrier->isOpen = true;
+            }
+            entry.barrier->condition.notify_one();
+        }
+    }
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/ImageManager.h b/libs/renderengine/gl/ImageManager.h
new file mode 100644
index 0000000..b5ba554
--- /dev/null
+++ b/libs/renderengine/gl/ImageManager.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2019 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 <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLESRenderEngine;
+
+class ImageManager {
+public:
+    struct Barrier {
+        std::mutex mutex;
+        std::condition_variable_any condition;
+        bool isOpen GUARDED_BY(mutex) = false;
+        status_t result GUARDED_BY(mutex) = NO_ERROR;
+    };
+    ImageManager(GLESRenderEngine* engine);
+    ~ImageManager();
+    void cacheAsync(const sp<GraphicBuffer>& buffer, const std::shared_ptr<Barrier>& barrier)
+            EXCLUDES(mMutex);
+    status_t cache(const sp<GraphicBuffer>& buffer);
+    void releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) EXCLUDES(mMutex);
+
+private:
+    struct QueueEntry {
+        enum class Operation { Delete, Insert };
+
+        Operation op = Operation::Delete;
+        sp<GraphicBuffer> buffer = nullptr;
+        uint64_t bufferId = 0;
+        std::shared_ptr<Barrier> barrier = nullptr;
+    };
+
+    void queueOperation(const QueueEntry&& entry);
+    void threadMain();
+    GLESRenderEngine* const mEngine;
+    std::thread mThread = std::thread([this]() { threadMain(); });
+    std::condition_variable_any mCondition;
+    std::mutex mMutex;
+    std::queue<QueueEntry> mQueue GUARDED_BY(mMutex);
+
+    bool mRunning GUARDED_BY(mMutex) = true;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 1c480a7..205782b 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -94,10 +94,20 @@
                                                const sp<Fence>& fence) = 0;
     // Caches Image resources for this buffer, but does not bind the buffer to
     // a particular texture.
-    virtual status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
+    // Note that work is deferred to an additional thread, i.e. this call
+    // is made asynchronously, but the caller can expect that cache/unbind calls
+    // are performed in a manner that's conflict serializable, i.e. unbinding
+    // a buffer should never occur before binding the buffer if the caller
+    // called {bind, cache}ExternalTextureBuffer before calling unbind.
+    virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
     // Removes internal resources referenced by the bufferId. This method should be
     // invoked when the caller will no longer hold a reference to a GraphicBuffer
     // and needs to clean up its resources.
+    // Note that work is deferred to an additional thread, i.e. this call
+    // is made asynchronously, but the caller can expect that cache/unbind calls
+    // are performed in a manner that's conflict serializable, i.e. unbinding
+    // a buffer should never occur before binding the buffer if the caller
+    // called {bind, cache}ExternalTextureBuffer before calling unbind.
     virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0;
     // When binding a native buffer, it must be done before setViewportAndProjection
     // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index f099cd2..0750e86 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -43,7 +43,7 @@
     MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
     MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
     MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
-    MOCK_METHOD1(cacheExternalTextureBuffer, status_t(const sp<GraphicBuffer>&));
+    MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp<GraphicBuffer>&));
     MOCK_METHOD3(bindExternalTextureBuffer,
                  status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&));
     MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 9b483ef..e98babc 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -31,6 +31,7 @@
         "libgui",
         "liblog",
         "libnativewindow",
+        "libprocessgroup",
         "libsync",
         "libui",
         "libutils",
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 7acaecf..f47c7fd 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
+#include <chrono>
+#include <condition_variable>
 
+#include <gtest/gtest.h>
 #include <renderengine/RenderEngine.h>
 #include <sync/sync.h>
 #include <ui/PixelFormat.h>
@@ -1001,8 +1003,15 @@
     invokeDraw(settings, layers, mBuffer);
     uint64_t bufferId = layer.source.buffer.buffer->getId();
     EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
-    sRE->unbindExternalTextureBuffer(bufferId);
+    std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+            sRE->unbindExternalTextureBufferForTesting(bufferId);
+    std::lock_guard<std::mutex> lock(barrier->mutex);
+    ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+                                            [&]() REQUIRES(barrier->mutex) {
+                                                return barrier->isOpen;
+                                            }));
     EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+    EXPECT_EQ(NO_ERROR, barrier->result);
 }
 
 TEST_F(RenderEngineTest, drawLayers_bindExternalBufferWithNullBuffer) {
@@ -1019,21 +1028,52 @@
     sRE->bindExternalTextureBuffer(texName, buf, nullptr);
     uint64_t bufferId = buf->getId();
     EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
-    sRE->unbindExternalTextureBuffer(bufferId);
+    std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+            sRE->unbindExternalTextureBufferForTesting(bufferId);
+    std::lock_guard<std::mutex> lock(barrier->mutex);
+    ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+                                            [&]() REQUIRES(barrier->mutex) {
+                                                return barrier->isOpen;
+                                            }));
+    EXPECT_EQ(NO_ERROR, barrier->result);
     EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
 }
 
 TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) {
-    status_t result = sRE->cacheExternalTextureBuffer(nullptr);
-    ASSERT_EQ(BAD_VALUE, result);
+    std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+            sRE->cacheExternalTextureBufferForTesting(nullptr);
+    std::lock_guard<std::mutex> lock(barrier->mutex);
+    ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+                                            [&]() REQUIRES(barrier->mutex) {
+                                                return barrier->isOpen;
+                                            }));
+    EXPECT_TRUE(barrier->isOpen);
+    EXPECT_EQ(BAD_VALUE, barrier->result);
 }
 
 TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) {
     sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
     uint64_t bufferId = buf->getId();
-    sRE->cacheExternalTextureBuffer(buf);
+    std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+            sRE->cacheExternalTextureBufferForTesting(buf);
+    {
+        std::lock_guard<std::mutex> lock(barrier->mutex);
+        ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+                                                [&]() REQUIRES(barrier->mutex) {
+                                                    return barrier->isOpen;
+                                                }));
+        EXPECT_EQ(NO_ERROR, barrier->result);
+    }
     EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
-    sRE->unbindExternalTextureBuffer(bufferId);
+    barrier = sRE->unbindExternalTextureBufferForTesting(bufferId);
+    {
+        std::lock_guard<std::mutex> lock(barrier->mutex);
+        ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+                                                [&]() REQUIRES(barrier->mutex) {
+                                                    return barrier->isOpen;
+                                                }));
+        EXPECT_EQ(NO_ERROR, barrier->result);
+    }
     EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
 }
 
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 2cc6857..2bbb0ee 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -187,3 +187,11 @@
     "tests",
     "tools",
 ]
+
+filegroup {
+    name: "libui_host_common",
+    srcs: [
+        "Rect.cpp",
+        "PixelFormat.cpp"
+    ],
+}
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index 127f7ee..5e0b094 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -44,11 +44,28 @@
 
 TEST_F(GraphicBufferTest, AllocateBadDimensions) {
     PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+    if (std::numeric_limits<size_t>::max() / std::numeric_limits<uint32_t>::max() /
+                bytesPerPixel(format) >=
+        std::numeric_limits<uint32_t>::max()) {
+        GTEST_SUCCEED() << "Cannot overflow with this format";
+    }
     uint32_t width, height;
     width = height = std::numeric_limits<uint32_t>::max();
     sp<GraphicBuffer> gb(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage,
                                            std::string("test")));
     ASSERT_EQ(BAD_VALUE, gb->initCheck());
+
+    const size_t targetArea = std::numeric_limits<size_t>::max() / bytesPerPixel(format);
+    const size_t widthCandidate = targetArea / std::numeric_limits<uint32_t>::max();
+    if (widthCandidate == 0) {
+        width = 1;
+    } else {
+        width = std::numeric_limits<uint32_t>::max();
+    }
+    height = (targetArea / width) + 1;
+    sp<GraphicBuffer> gb2(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage,
+                                            std::string("test")));
+    ASSERT_EQ(BAD_VALUE, gb2->initCheck());
 }
 
 TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) {
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 717f317..c7a8f5b 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -134,7 +134,12 @@
 
                     mActivationCount.add(list[i].sensorHandle, model);
 
-                    checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
+                    // Only disable all sensors on HAL 1.0 since HAL 2.0
+                    // handles this in its initialize method
+                    if (!mSensors->supportsMessageQueues()) {
+                        checkReturn(mSensors->activate(list[i].sensorHandle,
+                                    0 /* enabled */));
+                    }
                 }
             }));
 }
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 59ea9af..87bec11 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -132,13 +132,15 @@
     return inverse(tr);
 }
 
-bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
-                                     bool useIdentityTransform, Region& clearRegion,
-                                     const bool supportProtectedContent,
-                                     renderengine::LayerSettings& layer) {
+std::optional<renderengine::LayerSettings> BufferLayer::prepareClientComposition(
+        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
     ATRACE_CALL();
-    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
-                              supportProtectedContent, layer);
+
+    auto result = Layer::prepareClientComposition(targetSettings);
+    if (!result) {
+        return result;
+    }
+
     if (CC_UNLIKELY(mActiveBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
@@ -159,15 +161,16 @@
             under.orSelf(layer->visibleRegion);
         });
         // if not everything below us is covered, we plug the holes!
-        Region holes(clip.subtract(under));
+        Region holes(targetSettings.clip.subtract(under));
         if (!holes.isEmpty()) {
-            clearRegion.orSelf(holes);
+            targetSettings.clearRegion.orSelf(holes);
         }
-        return false;
+        return std::nullopt;
     }
-    bool blackOutLayer =
-            (isProtected() && !supportProtectedContent) || (isSecure() && !renderArea.isSecure());
+    bool blackOutLayer = (isProtected() && !targetSettings.supportProtectedContent) ||
+            (isSecure() && !targetSettings.isSecure);
     const State& s(getDrawingState());
+    auto& layer = *result;
     if (!blackOutLayer) {
         layer.source.buffer.buffer = mActiveBuffer;
         layer.source.buffer.isOpaque = isOpaque(s);
@@ -176,8 +179,7 @@
         layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
         layer.source.buffer.isY410BT2020 = isHdrY410();
         // TODO: we could be more subtle with isFixedSize()
-        const bool useFiltering = needsFiltering(renderArea.getDisplayDevice()) ||
-                renderArea.needsFiltering() || isFixedSize();
+        const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
@@ -244,7 +246,7 @@
         layer.alpha = 1.0;
     }
 
-    return true;
+    return result;
 }
 
 bool BufferLayer::isHdrY410() const {
@@ -572,21 +574,23 @@
 }
 
 bool BufferLayer::needsFiltering(const sp<const DisplayDevice>& displayDevice) const {
-    // If we are not capturing based on the state of a known display device, we
-    // only return mNeedsFiltering
+    // If we are not capturing based on the state of a known display device,
+    // just return false.
     if (displayDevice == nullptr) {
-        return mNeedsFiltering;
+        return false;
     }
 
     const auto outputLayer = findOutputLayerForDisplay(displayDevice);
     if (outputLayer == nullptr) {
-        return mNeedsFiltering;
+        return false;
     }
 
+    // We need filtering if the sourceCrop rectangle size does not match the
+    // displayframe rectangle size (not a 1:1 render)
     const auto& compositionState = outputLayer->getState();
     const auto displayFrame = compositionState.displayFrame;
     const auto sourceCrop = compositionState.sourceCrop;
-    return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+    return sourceCrop.getHeight() != displayFrame.getHeight() ||
             sourceCrop.getWidth() != displayFrame.getWidth();
 }
 
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index bb0205d..c86acf0 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -82,7 +82,6 @@
 
     bool isHdrY410() const override;
 
-    bool onPreComposition(nsecs_t refreshStartTime) override;
     bool onPostComposition(const std::optional<DisplayId>& displayId,
                            const std::shared_ptr<FenceTime>& glDoneFence,
                            const std::shared_ptr<FenceTime>& presentFence,
@@ -146,7 +145,13 @@
     virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
 
 protected:
-    void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const override;
+    /*
+     * compositionengine::LayerFE overrides
+     */
+    bool onPreComposition(nsecs_t) override;
+    void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+    std::optional<renderengine::LayerSettings> prepareClientComposition(
+            compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
 
     // Loads the corresponding system property once per process
     static bool latchUnsignaledBuffers();
@@ -163,15 +168,9 @@
 
     bool mRefreshPending{false};
 
-    // prepareClientLayer - constructs a RenderEngine layer for GPU composition.
-    bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
-                            bool useIdentityTransform, Region& clearRegion,
-                            const bool supportProtectedContent,
-                            renderengine::LayerSettings& layer) override;
-
 private:
     // Returns true if this layer requires filtering
-    bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const;
+    bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const override;
 
     uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
 
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 5e994b7..ea55795 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -470,7 +470,6 @@
         if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr ||
             oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) {
             mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE);
-            mRE.cacheExternalTextureBuffer(item.mGraphicBuffer);
         }
     }
 }
@@ -507,6 +506,12 @@
     ConsumerBase::dumpLocked(result, prefix);
 }
 
+BufferLayerConsumer::Image::Image(const sp<GraphicBuffer>& graphicBuffer,
+                                  renderengine::RenderEngine& engine)
+      : mGraphicBuffer(graphicBuffer), mRE(engine) {
+    mRE.cacheExternalTextureBuffer(mGraphicBuffer);
+}
+
 BufferLayerConsumer::Image::~Image() {
     if (mGraphicBuffer != nullptr) {
         ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId());
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 8536f6b..39ed370 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -223,8 +223,7 @@
     // Utility class for managing GraphicBuffer references into renderengine
     class Image {
     public:
-        Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine)
-              : mGraphicBuffer(graphicBuffer), mRE(engine) {}
+        Image(const sp<GraphicBuffer>& graphicBuffer, renderengine::RenderEngine& engine);
         virtual ~Image();
         const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
 
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index f15957a..b65d351 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -50,16 +50,14 @@
 
 ColorLayer::~ColorLayer() = default;
 
-bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
-                                    bool useIdentityTransform, Region& clearRegion,
-                                    const bool supportProtectedContent,
-                                    renderengine::LayerSettings& layer) {
-    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
-                              supportProtectedContent, layer);
-    half4 color(getColor());
-    half3 solidColor(color.r, color.g, color.b);
-    layer.source.solidColor = solidColor;
-    return true;
+std::optional<renderengine::LayerSettings> ColorLayer::prepareClientComposition(
+        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+    auto result = Layer::prepareClientComposition(targetSettings);
+    if (!result) {
+        return result;
+    }
+    result->source.solidColor = getColor().rgb;
+    return result;
 }
 
 bool ColorLayer::isVisible() const {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 2483ff0..015b939 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -39,16 +39,13 @@
 
     void commitTransaction(const State& stateToCommit) override;
 
-    bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
-
 protected:
-    virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
-                                    bool useIdentityTransform, Region& clearRegion,
-                                    const bool supportProtectedContent,
-                                    renderengine::LayerSettings& layer);
-
-private:
+    /*
+     * compositionengine::LayerFE overrides
+     */
     void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+    std::optional<renderengine::LayerSettings> prepareClientComposition(
+            compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
 
     std::shared_ptr<compositionengine::Layer> mCompositionLayer;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 1f2cae9..94fab1f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,6 +16,9 @@
 
 #pragma once
 
+#include <optional>
+
+#include <renderengine/LayerSettings.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
@@ -40,6 +43,34 @@
     // geometry state can be skipped.
     virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0;
 
+    struct ClientCompositionTargetSettings {
+        // The clip region, or visible region that is being rendered to
+        const Region& clip;
+
+        // If true, the layer should use an identity transform for its position
+        // transform. Used only by the captureScreen API call.
+        const bool useIdentityTransform;
+
+        // If set to true, the layer should enable filtering when rendering.
+        const bool needsFiltering;
+
+        // If set to true, the buffer is being sent to a destination that is
+        // expected to treat the buffer contents as secure.
+        const bool isSecure;
+
+        // If set to true, the target buffer has protected content support.
+        const bool supportProtectedContent;
+
+        // Modified by each call to prepareClientComposition to indicate the
+        // region of the target buffer that should be cleared.
+        Region& clearRegion;
+    };
+
+    // Returns the LayerSettings to pass to RenderEngine::drawLayers, or
+    // nullopt_t if the layer does not render
+    virtual std::optional<renderengine::LayerSettings> prepareClientComposition(
+            ClientCompositionTargetSettings&) = 0;
+
     // Called after the layer is displayed to update the presentation fence
     virtual void onLayerDisplayed(const sp<Fence>&) = 0;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 5b9e282..4dfcfa4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -19,8 +19,10 @@
 #include <cstdint>
 #include <optional>
 #include <string>
+#include <unordered_map>
 
 #include <math/mat4.h>
+#include <ui/Fence.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Region.h>
 #include <ui/Transform.h>
@@ -28,6 +30,10 @@
 
 #include "DisplayHardware/DisplayIdentification.h"
 
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
 namespace android::compositionengine {
 
 class DisplayColorProfile;
@@ -48,6 +54,12 @@
     using OutputLayers = std::vector<std::unique_ptr<compositionengine::OutputLayer>>;
     using ReleasedLayers = std::vector<wp<LayerFE>>;
 
+    struct FrameFences {
+        sp<Fence> presentFence{Fence::NO_FENCE};
+        sp<Fence> clientTargetAcquireFence{Fence::NO_FENCE};
+        std::unordered_map<HWC2::Layer*, sp<Fence>> layerFences;
+    };
+
     virtual ~Output();
 
     // Returns true if the output is valid. This is meant to be checked post-
@@ -132,15 +144,26 @@
     // Gets the ordered set of output layers for this output
     virtual const OutputLayers& getOutputLayersOrderedByZ() const = 0;
 
-    // Sets the new set of layers being released this frame.
+    // Sets the new set of layers being released this frame
     virtual void setReleasedLayers(ReleasedLayers&&) = 0;
 
     // Takes (moves) the set of layers being released this frame.
     virtual ReleasedLayers takeReleasedLayers() = 0;
 
+    // Signals that a frame is beginning on the output
+    virtual void beginFrame() = 0;
+
+    // Prepares a frame for display
+    virtual void prepareFrame() = 0;
+
+    // Posts the new frame, and sets release fences.
+    virtual void postFramebuffer() = 0;
+
 protected:
     virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
     virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
+    virtual void chooseCompositionStrategy() = 0;
+    virtual FrameFences presentAndGetFrameFences() = 0;
 };
 
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index d3a4e09..d7f00a9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -21,8 +21,13 @@
 
 #include <utils/StrongPointer.h>
 
+#include "DisplayHardware/ComposerHal.h"
 #include "DisplayHardware/DisplayIdentification.h"
 
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
 namespace android {
 
 namespace compositionengine {
@@ -73,6 +78,21 @@
     // skipped.
     virtual void writeStateToHWC(bool includeGeometry) = 0;
 
+    // Returns the HWC2::Layer associated with this layer, if it exists
+    virtual HWC2::Layer* getHwcLayer() const = 0;
+
+    // Returns true if the current layer state requires client composition
+    virtual bool requiresClientComposition() const = 0;
+
+    // Applies a HWC device requested composition type change
+    virtual void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) = 0;
+
+    // Prepares to apply any HWC device layer requests
+    virtual void prepareForDeviceLayerRequests() = 0;
+
+    // Applies a HWC device layer request
+    virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0;
+
     // Debugging
     virtual void dump(std::string& result) const = 0;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 9bff73e..6859846 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -71,7 +71,7 @@
     virtual status_t beginFrame(bool mustRecompose) = 0;
 
     // Prepares the frame for rendering
-    virtual status_t prepareFrame() = 0;
+    virtual void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) = 0;
 
     // Allocates a buffer as scratch space for GPU composition
     virtual sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 1265533..795061a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -16,12 +16,13 @@
 
 #pragma once
 
-#include <memory>
-
 #include <compositionengine/Display.h>
 #include <compositionengine/impl/Output.h>
 
+#include <memory>
+
 #include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/HWComposer.h"
 
 namespace android::compositionengine {
 
@@ -40,6 +41,8 @@
     void dump(std::string&) const override;
     void setColorTransform(const mat4&) override;
     void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
+    void chooseCompositionStrategy() override;
+    compositionengine::Output::FrameFences presentAndGetFrameFences() override;
 
     // compositionengine::Display overrides
     const std::optional<DisplayId>& getId() const override;
@@ -49,12 +52,22 @@
     void createDisplayColorProfile(compositionengine::DisplayColorProfileCreationArgs&&) override;
     void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override;
 
+    // Internal helpers used by chooseCompositionStrategy()
+    using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
+    using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests;
+    using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests;
+    virtual bool anyLayersRequireClientComposition() const;
+    virtual bool allLayersRequireClientComposition() const;
+    virtual void applyChangedTypesToLayers(const ChangedTypes&);
+    virtual void applyDisplayRequests(const DisplayRequests&);
+    virtual void applyLayerRequestsToLayers(const LayerRequests&);
+
 private:
     const bool mIsVirtual;
     std::optional<DisplayId> mId;
 };
 
-std::shared_ptr<compositionengine::Display> createDisplay(
-        const compositionengine::CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+std::shared_ptr<Display> createDisplay(const compositionengine::CompositionEngine&,
+                                       compositionengine::DisplayCreationArgs&&);
 } // namespace impl
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 20812d2..5f4a764 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -75,12 +75,18 @@
     void setReleasedLayers(ReleasedLayers&&) override;
     ReleasedLayers takeReleasedLayers() override;
 
+    void beginFrame() override;
+    void prepareFrame() override;
+    void postFramebuffer() override;
+
     // Testing
     void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
     void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
 
 protected:
     const CompositionEngine& getCompositionEngine() const;
+    void chooseCompositionStrategy() override;
+    compositionengine::Output::FrameFences presentAndGetFrameFences() override;
     void dumpBase(std::string&) const;
 
 private:
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 45b8308..1078f11 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -35,6 +35,16 @@
     // If false, this output is not considered secure
     bool isSecure{false};
 
+    // If true, the current frame on this output uses client composition
+    bool usesClientComposition{false};
+
+    // If true, the current frame on this output uses device composition
+    bool usesDeviceComposition{false};
+
+    // If true, the client target should be flipped when performing client
+    // composition
+    bool flipClientTarget{false};
+
     // If true, this output displays layers that are internal-only
     bool layerStackInternal{false};
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 708f3a1..d8ad02a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -50,6 +50,12 @@
     void updateCompositionState(bool) override;
     void writeStateToHWC(bool) override;
 
+    HWC2::Layer* getHwcLayer() const override;
+    bool requiresClientComposition() const override;
+    void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override;
+    void prepareForDeviceLayerRequests() override;
+    void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
+
     void dump(std::string& result) const override;
 
     virtual FloatRect calculateOutputSourceCrop() const;
@@ -66,6 +72,8 @@
     void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
     void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
     void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
+    void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from,
+                                               Hwc2::IComposerClient::Composition to) const;
 
     const compositionengine::Output& mOutput;
     std::shared_ptr<compositionengine::Layer> mLayer;
@@ -79,4 +87,4 @@
         std::shared_ptr<compositionengine::Layer>, sp<compositionengine::LayerFE>);
 
 } // namespace impl
-} // namespace android::compositionengine
\ No newline at end of file
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index e4c9c80..0a04462 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -52,7 +52,7 @@
     void setDisplaySize(const ui::Size&) override;
     void setProtected(bool useProtected) override;
     status_t beginFrame(bool mustRecompose) override;
-    status_t prepareFrame() override;
+    void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override;
     sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override;
     void queueBuffer(base::unique_fd&& readyFence) override;
     void onPresentDisplayCompleted() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 952f702..48c2dbf 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -33,6 +33,9 @@
     MOCK_METHOD1(onPreComposition, bool(nsecs_t));
 
     MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool));
+    MOCK_METHOD1(prepareClientComposition,
+                 std::optional<renderengine::LayerSettings>(
+                         compositionengine::LayerFE::ClientCompositionTargetSettings&));
     MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
 
     MOCK_CONST_METHOD0(getDebugName, const char*());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 924d72c..d494413 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -72,6 +72,13 @@
 
     MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&));
     MOCK_METHOD0(takeReleasedLayers, ReleasedLayers());
+
+    MOCK_METHOD0(beginFrame, void());
+    MOCK_METHOD0(prepareFrame, void());
+    MOCK_METHOD0(chooseCompositionStrategy, void());
+
+    MOCK_METHOD0(postFramebuffer, void());
+    MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index dab8b9d..195648f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -41,6 +41,12 @@
     MOCK_METHOD1(updateCompositionState, void(bool));
     MOCK_METHOD1(writeStateToHWC, void(bool));
 
+    MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*());
+    MOCK_CONST_METHOD0(requiresClientComposition, bool());
+    MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition));
+    MOCK_METHOD0(prepareForDeviceLayerRequests, void());
+    MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request));
+
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 146a2ea..ba6746a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -37,7 +37,7 @@
     MOCK_METHOD1(setProtected, void(bool));
     MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
     MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
-    MOCK_METHOD0(prepareFrame, status_t());
+    MOCK_METHOD2(prepareFrame, void(bool, bool));
     MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
     MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
     MOCK_METHOD0(onPresentDisplayCompleted, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 8520d70..6831901 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -21,13 +21,15 @@
 #include <compositionengine/impl/Display.h>
 #include <compositionengine/impl/DisplayColorProfile.h>
 #include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputLayer.h>
 #include <compositionengine/impl/RenderSurface.h>
+#include <utils/Trace.h>
 
 #include "DisplayHardware/HWComposer.h"
 
 namespace android::compositionengine::impl {
 
-std::shared_ptr<compositionengine::Display> createDisplay(
+std::shared_ptr<Display> createDisplay(
         const compositionengine::CompositionEngine& compositionEngine,
         compositionengine::DisplayCreationArgs&& args) {
     return std::make_shared<Display>(compositionEngine, std::move(args));
@@ -124,4 +126,118 @@
                                                                   std::move(args)));
 }
 
+void Display::chooseCompositionStrategy() {
+    ATRACE_CALL();
+    ALOGV(__FUNCTION__);
+
+    // Default to the base settings -- client composition only.
+    Output::chooseCompositionStrategy();
+
+    // If we don't have a HWC display, then we are done
+    if (!mId) {
+        return;
+    }
+
+    // Get any composition changes requested by the HWC device, and apply them.
+    std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+    auto& hwc = getCompositionEngine().getHwComposer();
+    if (status_t result = hwc.getDeviceCompositionChanges(*mId, anyLayersRequireClientComposition(),
+                                                          &changes);
+        result != NO_ERROR) {
+        ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
+              strerror(-result));
+        return;
+    }
+    if (changes) {
+        applyChangedTypesToLayers(changes->changedTypes);
+        applyDisplayRequests(changes->displayRequests);
+        applyLayerRequestsToLayers(changes->layerRequests);
+    }
+
+    // Determine what type of composition we are doing from the final state
+    auto& state = editState();
+    state.usesClientComposition = anyLayersRequireClientComposition();
+    state.usesDeviceComposition = !allLayersRequireClientComposition();
+}
+
+bool Display::anyLayersRequireClientComposition() const {
+    const auto& layers = getOutputLayersOrderedByZ();
+    return std::any_of(layers.cbegin(), layers.cend(),
+                       [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+bool Display::allLayersRequireClientComposition() const {
+    const auto& layers = getOutputLayersOrderedByZ();
+    return std::all_of(layers.cbegin(), layers.cend(),
+                       [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+void Display::applyChangedTypesToLayers(const ChangedTypes& changedTypes) {
+    if (changedTypes.empty()) {
+        return;
+    }
+
+    for (auto& layer : getOutputLayersOrderedByZ()) {
+        auto hwcLayer = layer->getHwcLayer();
+        if (!hwcLayer) {
+            continue;
+        }
+
+        if (auto it = changedTypes.find(hwcLayer); it != changedTypes.end()) {
+            layer->applyDeviceCompositionTypeChange(
+                    static_cast<Hwc2::IComposerClient::Composition>(it->second));
+        }
+    }
+}
+
+void Display::applyDisplayRequests(const DisplayRequests& displayRequests) {
+    auto& state = editState();
+    state.flipClientTarget = (static_cast<uint32_t>(displayRequests) &
+                              static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0;
+    // Note: HWC2::DisplayRequest::WriteClientTargetToOutput is currently ignored.
+}
+
+void Display::applyLayerRequestsToLayers(const LayerRequests& layerRequests) {
+    for (auto& layer : getOutputLayersOrderedByZ()) {
+        layer->prepareForDeviceLayerRequests();
+
+        auto hwcLayer = layer->getHwcLayer();
+        if (!hwcLayer) {
+            continue;
+        }
+
+        if (auto it = layerRequests.find(hwcLayer); it != layerRequests.end()) {
+            layer->applyDeviceLayerRequest(
+                    static_cast<Hwc2::IComposerClient::LayerRequest>(it->second));
+        }
+    }
+}
+
+compositionengine::Output::FrameFences Display::presentAndGetFrameFences() {
+    auto result = impl::Output::presentAndGetFrameFences();
+
+    if (!mId) {
+        return result;
+    }
+
+    auto& hwc = getCompositionEngine().getHwComposer();
+    hwc.presentAndGetReleaseFences(*mId);
+
+    result.presentFence = hwc.getPresentFence(*mId);
+
+    // TODO(b/121291683): Change HWComposer call to return entire map
+    for (const auto& layer : getOutputLayersOrderedByZ()) {
+        auto hwcLayer = layer->getHwcLayer();
+        if (!hwcLayer) {
+            continue;
+        }
+
+        result.layerFences.emplace(hwcLayer, hwc.getLayerReleaseFence(*mId, hwcLayer));
+    }
+
+    hwc.clearReleaseFences(*mId);
+
+    return result;
+}
+
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 845e3c6..b411e0a 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -22,6 +22,7 @@
 #include <compositionengine/impl/Output.h>
 #include <compositionengine/impl/OutputLayer.h>
 #include <ui/DebugUtils.h>
+#include <utils/Trace.h>
 
 namespace android::compositionengine {
 
@@ -250,9 +251,115 @@
     return std::move(mReleasedLayers);
 }
 
+void Output::beginFrame() {
+    const bool dirty = !getDirtyRegion(false).isEmpty();
+    const bool empty = mOutputLayersOrderedByZ.empty();
+    const bool wasEmpty = !mState.lastCompositionHadVisibleLayers;
+
+    // If nothing has changed (!dirty), don't recompose.
+    // If something changed, but we don't currently have any visible layers,
+    //   and didn't when we last did a composition, then skip it this time.
+    // The second rule does two things:
+    // - When all layers are removed from a display, we'll emit one black
+    //   frame, then nothing more until we get new layers.
+    // - When a display is created with a private layer stack, we won't
+    //   emit any black frames until a layer is added to the layer stack.
+    const bool mustRecompose = dirty && !(empty && wasEmpty);
+
+    const char flagPrefix[] = {'-', '+'};
+    static_cast<void>(flagPrefix);
+    ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__,
+             mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty],
+             flagPrefix[empty], flagPrefix[wasEmpty]);
+
+    mRenderSurface->beginFrame(mustRecompose);
+
+    if (mustRecompose) {
+        mState.lastCompositionHadVisibleLayers = !empty;
+    }
+}
+
+void Output::prepareFrame() {
+    ATRACE_CALL();
+    ALOGV(__FUNCTION__);
+
+    if (!mState.isEnabled) {
+        return;
+    }
+
+    chooseCompositionStrategy();
+
+    mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition);
+}
+
+void Output::postFramebuffer() {
+    ATRACE_CALL();
+    ALOGV(__FUNCTION__);
+
+    if (!getState().isEnabled) {
+        return;
+    }
+
+    mRenderSurface->onPresentDisplayCompleted();
+
+    auto frame = presentAndGetFrameFences();
+
+    for (auto& layer : getOutputLayersOrderedByZ()) {
+        // The layer buffer from the previous frame (if any) is released
+        // by HWC only when the release fence from this frame (if any) is
+        // signaled.  Always get the release fence from HWC first.
+        sp<Fence> releaseFence = Fence::NO_FENCE;
+
+        if (auto hwcLayer = layer->getHwcLayer()) {
+            if (auto f = frame.layerFences.find(hwcLayer); f != frame.layerFences.end()) {
+                releaseFence = f->second;
+            }
+        }
+
+        // If the layer was client composited in the previous frame, we
+        // need to merge with the previous client target acquire fence.
+        // Since we do not track that, always merge with the current
+        // client target acquire fence when it is available, even though
+        // this is suboptimal.
+        // TODO(b/121291683): Track previous frame client target acquire fence.
+        if (mState.usesClientComposition) {
+            releaseFence =
+                    Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
+        }
+
+        layer->getLayerFE().onLayerDisplayed(releaseFence);
+    }
+
+    // We've got a list of layers needing fences, that are disjoint with
+    // getOutputLayersOrderedByZ.  The best we can do is to
+    // supply them with the present fence.
+    for (auto& weakLayer : mReleasedLayers) {
+        if (auto layer = weakLayer.promote(); layer != nullptr) {
+            layer->onLayerDisplayed(frame.presentFence);
+        }
+    }
+
+    // Clear out the released layers now that we're done with them.
+    mReleasedLayers.clear();
+}
+
 void Output::dirtyEntireOutput() {
     mState.dirtyRegion.set(mState.bounds);
 }
 
+void Output::chooseCompositionStrategy() {
+    // The base output implementation can only do client composition
+    mState.usesClientComposition = true;
+    mState.usesDeviceComposition = false;
+}
+
+compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
+    compositionengine::Output::FrameFences result;
+    if (mState.usesClientComposition) {
+        result.clientTargetAcquireFence = mRenderSurface->getClientTargetAcquireFence();
+    }
+    return result;
+}
+
 } // namespace impl
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 0b15dad..3e47fe2 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -24,6 +24,10 @@
     dumpVal(out, "isEnabled", isEnabled);
     dumpVal(out, "isSecure", isSecure);
 
+    dumpVal(out, "usesClientComposition", usesClientComposition);
+    dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
+    dumpVal(out, "flipClientTarget", flipClientTarget);
+
     dumpVal(out, "layerStack", layerStackId);
     dumpVal(out, "layerStackInternal", layerStackInternal);
 
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index ebfc704..6e744b9 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -550,6 +550,70 @@
     }
 }
 
+HWC2::Layer* OutputLayer::getHwcLayer() const {
+    return mState.hwc ? mState.hwc->hwcLayer.get() : nullptr;
+}
+
+bool OutputLayer::requiresClientComposition() const {
+    return !mState.hwc ||
+            mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
+}
+
+void OutputLayer::detectDisallowedCompositionTypeChange(
+        Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const {
+    bool result = false;
+    switch (from) {
+        case Hwc2::IComposerClient::Composition::INVALID:
+        case Hwc2::IComposerClient::Composition::CLIENT:
+            result = false;
+            break;
+
+        case Hwc2::IComposerClient::Composition::DEVICE:
+        case Hwc2::IComposerClient::Composition::SOLID_COLOR:
+            result = (to == Hwc2::IComposerClient::Composition::CLIENT);
+            break;
+
+        case Hwc2::IComposerClient::Composition::CURSOR:
+        case Hwc2::IComposerClient::Composition::SIDEBAND:
+            result = (to == Hwc2::IComposerClient::Composition::CLIENT ||
+                      to == Hwc2::IComposerClient::Composition::DEVICE);
+            break;
+    }
+
+    if (!result) {
+        ALOGE("[%s] Invalid device requested composition type change: %s (%d) --> %s (%d)",
+              mLayerFE->getDebugName(), toString(from).c_str(), static_cast<int>(from),
+              toString(to).c_str(), static_cast<int>(to));
+    }
+}
+
+void OutputLayer::applyDeviceCompositionTypeChange(
+        Hwc2::IComposerClient::Composition compositionType) {
+    LOG_FATAL_IF(!mState.hwc);
+    auto& hwcState = *mState.hwc;
+
+    detectDisallowedCompositionTypeChange(hwcState.hwcCompositionType, compositionType);
+
+    hwcState.hwcCompositionType = compositionType;
+}
+
+void OutputLayer::prepareForDeviceLayerRequests() {
+    mState.clearClientTarget = false;
+}
+
+void OutputLayer::applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) {
+    switch (request) {
+        case Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET:
+            mState.clearClientTarget = true;
+            break;
+
+        default:
+            ALOGE("[%s] Unknown device layer request %s (%d)", mLayerFE->getDebugName(),
+                  toString(request).c_str(), static_cast<int>(request));
+            break;
+    }
+}
+
 void OutputLayer::dump(std::string& out) const {
     using android::base::StringAppendF;
 
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 8a91316..1ce6b4c 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -23,6 +23,7 @@
 #include <compositionengine/DisplaySurface.h>
 #include <compositionengine/RenderSurfaceCreationArgs.h>
 #include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/impl/RenderSurface.h>
 #include <log/log.h>
 #include <renderengine/RenderEngine.h>
@@ -110,24 +111,13 @@
     return mDisplaySurface->beginFrame(mustRecompose);
 }
 
-status_t RenderSurface::prepareFrame() {
-    auto& hwc = mCompositionEngine.getHwComposer();
-    const auto id = mDisplay.getId();
-    if (id) {
-        status_t error = hwc.prepare(*id, mDisplay);
-        if (error != NO_ERROR) {
-            return error;
-        }
-    }
-
+void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComposition) {
     DisplaySurface::CompositionType compositionType;
-    const bool hasClient = hwc.hasClientComposition(id);
-    const bool hasDevice = hwc.hasDeviceComposition(id);
-    if (hasClient && hasDevice) {
+    if (usesClientComposition && usesDeviceComposition) {
         compositionType = DisplaySurface::COMPOSITION_MIXED;
-    } else if (hasClient) {
+    } else if (usesClientComposition) {
         compositionType = DisplaySurface::COMPOSITION_GLES;
-    } else if (hasDevice) {
+    } else if (usesDeviceComposition) {
         compositionType = DisplaySurface::COMPOSITION_HWC;
     } else {
         // Nothing to do -- when turning the screen off we get a frame like
@@ -135,7 +125,11 @@
         // will do a prepare/set cycle.
         compositionType = DisplaySurface::COMPOSITION_HWC;
     }
-    return mDisplaySurface->prepareFrame(compositionType);
+
+    if (status_t result = mDisplaySurface->prepareFrame(compositionType); result != NO_ERROR) {
+        ALOGE("updateCompositionType failed for %s: %d (%s)", mDisplay.getName().c_str(), result,
+              strerror(-result));
+    }
 }
 
 sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) {
@@ -163,10 +157,9 @@
 }
 
 void RenderSurface::queueBuffer(base::unique_fd&& readyFence) {
-    auto& hwc = mCompositionEngine.getHwComposer();
-    const auto id = mDisplay.getId();
+    auto& state = mDisplay.getState();
 
-    if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) {
+    if (state.usesClientComposition || state.flipClientTarget) {
         // hasFlipClientTargetRequest could return true even if we haven't
         // dequeued a buffer before. Try dequeueing one if we don't have a
         // buffer ready.
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index f0aea25..e3be0d7 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -24,33 +24,54 @@
 #include <compositionengine/mock/CompositionEngine.h>
 #include <compositionengine/mock/DisplayColorProfile.h>
 #include <compositionengine/mock/NativeWindow.h>
+#include <compositionengine/mock/OutputLayer.h>
 #include <compositionengine/mock/RenderSurface.h>
 #include <gtest/gtest.h>
 
+#include "MockHWC2.h"
 #include "MockHWComposer.h"
 
 namespace android::compositionengine {
 namespace {
 
 using testing::_;
+using testing::DoAll;
 using testing::Return;
 using testing::ReturnRef;
+using testing::Sequence;
+using testing::SetArgPointee;
 using testing::StrictMock;
 
 constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
 
-class DisplayTest : public testing::Test {
-public:
-    ~DisplayTest() override = default;
+struct DisplayTest : public testing::Test {
+    DisplayTest() {
+        EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+        EXPECT_CALL(*mLayer1, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer1));
+        EXPECT_CALL(*mLayer2, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer2));
+        EXPECT_CALL(*mLayer3, getHwcLayer()).WillRepeatedly(Return(nullptr));
+
+        std::vector<std::unique_ptr<OutputLayer>> layers;
+        layers.emplace_back(mLayer1);
+        layers.emplace_back(mLayer2);
+        layers.emplace_back(mLayer3);
+        mDisplay.setOutputLayersOrderedByZ(std::move(layers));
+    }
 
     StrictMock<android::mock::HWComposer> mHwComposer;
     StrictMock<mock::CompositionEngine> mCompositionEngine;
     sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
+    StrictMock<HWC2::mock::Layer> mHWC2Layer1;
+    StrictMock<HWC2::mock::Layer> mHWC2Layer2;
+    StrictMock<HWC2::mock::Layer> mHWC2LayerUnknown;
+    mock::OutputLayer* mLayer1 = new StrictMock<mock::OutputLayer>();
+    mock::OutputLayer* mLayer2 = new StrictMock<mock::OutputLayer>();
+    mock::OutputLayer* mLayer3 = new StrictMock<mock::OutputLayer>();
     impl::Display mDisplay{mCompositionEngine,
                            DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
 };
 
-/* ------------------------------------------------------------------------
+/*
  * Basic construction
  */
 
@@ -90,13 +111,11 @@
     }
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Display::disconnect()
  */
 
 TEST_F(DisplayTest, disconnectDisconnectsDisplay) {
-    EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
-
     // The first call to disconnect will disconnect the display with the HWC and
     // set mHwcId to -1.
     EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1);
@@ -109,7 +128,7 @@
     EXPECT_FALSE(mDisplay.getId());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Display::setColorTransform()
  */
 
@@ -117,8 +136,6 @@
     // Identity matrix sets an identity state value
     const mat4 identity;
 
-    EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
-
     EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1);
 
     mDisplay.setColorTransform(identity);
@@ -135,7 +152,7 @@
     EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Display::setColorMode()
  */
 
@@ -145,7 +162,6 @@
     mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
     mDisplay.setDisplayColorProfileForTest(std::unique_ptr<DisplayColorProfile>(colorProfile));
 
-    EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
     EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _))
             .WillRepeatedly(Return(ui::Dataspace::UNKNOWN));
 
@@ -202,7 +218,7 @@
     EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Display::createDisplayColorProfile()
  */
 
@@ -214,7 +230,7 @@
     EXPECT_TRUE(mDisplay.getDisplayColorProfile() != nullptr);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Display::createRenderSurface()
  */
 
@@ -225,5 +241,266 @@
     EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr);
 }
 
+/*
+ * Display::chooseCompositionStrategy()
+ */
+
+struct DisplayChooseCompositionStrategyTest : public testing::Test {
+    struct DisplayPartialMock : public impl::Display {
+        DisplayPartialMock(const compositionengine::CompositionEngine& compositionEngine,
+                           compositionengine::DisplayCreationArgs&& args)
+              : impl::Display(compositionEngine, std::move(args)) {}
+
+        // Sets up the helper functions called by chooseCompositionStrategy to
+        // use a mock implementations.
+        MOCK_CONST_METHOD0(anyLayersRequireClientComposition, bool());
+        MOCK_CONST_METHOD0(allLayersRequireClientComposition, bool());
+        MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&));
+        MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&));
+        MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&));
+    };
+
+    DisplayChooseCompositionStrategyTest() {
+        EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+    }
+
+    StrictMock<android::mock::HWComposer> mHwComposer;
+    StrictMock<mock::CompositionEngine> mCompositionEngine;
+    StrictMock<DisplayPartialMock>
+            mDisplay{mCompositionEngine,
+                     DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+};
+
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) {
+    impl::Display nonHwcDisplay{mCompositionEngine, DisplayCreationArgsBuilder().build()};
+    EXPECT_FALSE(nonHwcDisplay.getId());
+
+    nonHwcDisplay.chooseCompositionStrategy();
+
+    auto& state = nonHwcDisplay.getState();
+    EXPECT_TRUE(state.usesClientComposition);
+    EXPECT_FALSE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) {
+    EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false));
+    EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, false, _))
+            .WillOnce(Return(INVALID_OPERATION));
+
+    mDisplay.chooseCompositionStrategy();
+
+    auto& state = mDisplay.getState();
+    EXPECT_TRUE(state.usesClientComposition);
+    EXPECT_FALSE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) {
+    // Since two calls are made to anyLayersRequireClientComposition with different return values,
+    // use a Sequence to control the matching so the values are returned in a known order.
+    Sequence s;
+    EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true));
+    EXPECT_CALL(mDisplay, anyLayersRequireClientComposition())
+            .InSequence(s)
+            .WillOnce(Return(false));
+
+    EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _))
+            .WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+    mDisplay.chooseCompositionStrategy();
+
+    auto& state = mDisplay.getState();
+    EXPECT_FALSE(state.usesClientComposition);
+    EXPECT_TRUE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
+    android::HWComposer::DeviceRequestedChanges changes{
+            {{nullptr, HWC2::Composition::Client}},
+            HWC2::DisplayRequest::FlipClientTarget,
+            {{nullptr, HWC2::LayerRequest::ClearClientTarget}},
+    };
+
+    // Since two calls are made to anyLayersRequireClientComposition with different return values,
+    // use a Sequence to control the matching so the values are returned in a known order.
+    Sequence s;
+    EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true));
+    EXPECT_CALL(mDisplay, anyLayersRequireClientComposition())
+            .InSequence(s)
+            .WillOnce(Return(false));
+
+    EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _))
+            .WillOnce(DoAll(SetArgPointee<2>(changes), Return(NO_ERROR)));
+    EXPECT_CALL(mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1);
+    EXPECT_CALL(mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1);
+    EXPECT_CALL(mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1);
+    EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+    mDisplay.chooseCompositionStrategy();
+
+    auto& state = mDisplay.getState();
+    EXPECT_FALSE(state.usesClientComposition);
+    EXPECT_TRUE(state.usesDeviceComposition);
+}
+
+/*
+ * Display::anyLayersRequireClientComposition()
+ */
+
+TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) {
+    EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(false));
+
+    EXPECT_FALSE(mDisplay.anyLayersRequireClientComposition());
+}
+
+TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) {
+    EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+
+    EXPECT_TRUE(mDisplay.anyLayersRequireClientComposition());
+}
+
+/*
+ * Display::allLayersRequireClientComposition()
+ */
+
+TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) {
+    EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
+    EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+    EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(true));
+
+    EXPECT_TRUE(mDisplay.allLayersRequireClientComposition());
+}
+
+TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) {
+    EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
+    EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+
+    EXPECT_FALSE(mDisplay.allLayersRequireClientComposition());
+}
+
+/*
+ * Display::applyChangedTypesToLayers()
+ */
+
+TEST_F(DisplayTest, applyChangedTypesToLayersTakesEarlyOutIfNoChangedLayers) {
+    mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes());
+}
+
+TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) {
+    EXPECT_CALL(*mLayer1,
+                applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT))
+            .Times(1);
+    EXPECT_CALL(*mLayer2,
+                applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::DEVICE))
+            .Times(1);
+
+    mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes{
+            {&mHWC2Layer1, HWC2::Composition::Client},
+            {&mHWC2Layer2, HWC2::Composition::Device},
+            {&mHWC2LayerUnknown, HWC2::Composition::SolidColor},
+    });
+}
+
+/*
+ * Display::applyDisplayRequests()
+ */
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesNoRequests) {
+    mDisplay.applyDisplayRequests(static_cast<HWC2::DisplayRequest>(0));
+
+    auto& state = mDisplay.getState();
+    EXPECT_FALSE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesFlipClientTarget) {
+    mDisplay.applyDisplayRequests(HWC2::DisplayRequest::FlipClientTarget);
+
+    auto& state = mDisplay.getState();
+    EXPECT_TRUE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesWriteClientTargetToOutput) {
+    mDisplay.applyDisplayRequests(HWC2::DisplayRequest::WriteClientTargetToOutput);
+
+    auto& state = mDisplay.getState();
+    EXPECT_FALSE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) {
+    mDisplay.applyDisplayRequests(static_cast<HWC2::DisplayRequest>(~0));
+
+    auto& state = mDisplay.getState();
+    EXPECT_TRUE(state.flipClientTarget);
+}
+
+/*
+ * Display::applyLayerRequestsToLayers()
+ */
+
+TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) {
+    EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
+    EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
+    EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+
+    mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests());
+}
+
+TEST_F(DisplayTest, applyLayerRequestsToLayers2) {
+    EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
+    EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
+    EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+
+    EXPECT_CALL(*mLayer1,
+                applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET))
+            .Times(1);
+
+    mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests{
+            {&mHWC2Layer1, HWC2::LayerRequest::ClearClientTarget},
+            {&mHWC2LayerUnknown, HWC2::LayerRequest::ClearClientTarget},
+    });
+}
+
+/*
+ * Display::presentAndGetFrameFences()
+ */
+
+TEST_F(DisplayTest, presentAndGetFrameFencesReturnsNoFencesOnNonHwcDisplay) {
+    auto nonHwcDisplay{
+            impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+    auto result = nonHwcDisplay->presentAndGetFrameFences();
+
+    ASSERT_TRUE(result.presentFence.get());
+    EXPECT_FALSE(result.presentFence->isValid());
+    EXPECT_EQ(0u, result.layerFences.size());
+}
+
+TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) {
+    sp<Fence> presentFence = new Fence();
+    sp<Fence> layer1Fence = new Fence();
+    sp<Fence> layer2Fence = new Fence();
+
+    EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(DEFAULT_DISPLAY_ID)).Times(1);
+    EXPECT_CALL(mHwComposer, getPresentFence(DEFAULT_DISPLAY_ID)).WillOnce(Return(presentFence));
+    EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer1))
+            .WillOnce(Return(layer1Fence));
+    EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer2))
+            .WillOnce(Return(layer2Fence));
+    EXPECT_CALL(mHwComposer, clearReleaseFences(DEFAULT_DISPLAY_ID)).Times(1);
+
+    auto result = mDisplay.presentAndGetFrameFences();
+
+    EXPECT_EQ(presentFence, result.presentFence);
+
+    EXPECT_EQ(2u, result.layerFences.size());
+    ASSERT_EQ(1, result.layerFences.count(&mHWC2Layer1));
+    EXPECT_EQ(layer1Fence, result.layerFences[&mHWC2Layer1]);
+    ASSERT_EQ(1, result.layerFences.count(&mHWC2Layer2));
+    EXPECT_EQ(layer2Fence, result.layerFences[&mHWC2Layer2]);
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 94349de..5cfec77 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -40,7 +40,9 @@
                  std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
     MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
     MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
-    MOCK_METHOD2(prepare, status_t(DisplayId, const compositionengine::Output&));
+    MOCK_METHOD3(getDeviceCompositionChanges,
+                 status_t(DisplayId, bool,
+                          std::optional<android::HWComposer::DeviceRequestedChanges>*));
     MOCK_METHOD5(setClientTarget,
                  status_t(DisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
                           ui::Dataspace));
@@ -50,8 +52,6 @@
     MOCK_METHOD2(setColorTransform, status_t(DisplayId, const mat4&));
     MOCK_METHOD1(disconnectDisplay, void(DisplayId));
     MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional<DisplayId>&));
-    MOCK_CONST_METHOD1(hasFlipClientTargetRequest, bool(const std::optional<DisplayId>&));
-    MOCK_CONST_METHOD1(hasClientComposition, bool(const std::optional<DisplayId>&));
     MOCK_CONST_METHOD1(getPresentFence, sp<Fence>(DisplayId));
     MOCK_CONST_METHOD2(getLayerReleaseFence, sp<Fence>(DisplayId, HWC2::Layer*));
     MOCK_METHOD3(setOutputBuffer, status_t(DisplayId, const sp<Fence>&, const sp<GraphicBuffer>&));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 7b9528b..a5428ad 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -56,8 +56,7 @@
     return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a;
 }
 
-class OutputLayerTest : public testing::Test {
-public:
+struct OutputLayerTest : public testing::Test {
     OutputLayerTest() {
         EXPECT_CALL(*mLayerFE, getDebugName()).WillRepeatedly(Return("Test LayerFE"));
         EXPECT_CALL(mOutput, getName()).WillRepeatedly(ReturnRef(kOutputName));
@@ -66,8 +65,6 @@
         EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
     }
 
-    ~OutputLayerTest() override = default;
-
     compositionengine::mock::Output mOutput;
     std::shared_ptr<compositionengine::mock::Layer> mLayer{
             new StrictMock<compositionengine::mock::Layer>()};
@@ -784,5 +781,99 @@
     mOutputLayer.writeStateToHWC(false);
 }
 
+/*
+ * OutputLayer::getHwcLayer()
+ */
+
+TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcState) {
+    mOutputLayer.editState().hwc.reset();
+
+    EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr);
+}
+
+TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcLayer) {
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+
+    EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr);
+}
+
+TEST_F(OutputLayerTest, getHwcLayerReturnsHwcLayer) {
+    auto hwcLayer = std::make_shared<StrictMock<HWC2::mock::Layer>>();
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{hwcLayer};
+
+    EXPECT_EQ(hwcLayer.get(), mOutputLayer.getHwcLayer());
+}
+
+/*
+ * OutputLayer::requiresClientComposition()
+ */
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfNoHWC2State) {
+    mOutputLayer.editState().hwc.reset();
+
+    EXPECT_TRUE(mOutputLayer.requiresClientComposition());
+}
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfSetToClientComposition) {
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+    mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+
+    EXPECT_TRUE(mOutputLayer.requiresClientComposition());
+}
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsFalseIfSetToDeviceComposition) {
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+    mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+    EXPECT_FALSE(mOutputLayer.requiresClientComposition());
+}
+
+/*
+ * OutputLayer::applyDeviceCompositionTypeChange()
+ */
+
+TEST_F(OutputLayerTest, applyDeviceCompositionTypeChangeSetsNewType) {
+    mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+    mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+    mOutputLayer.applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT);
+
+    ASSERT_TRUE(mOutputLayer.getState().hwc);
+    EXPECT_EQ(Hwc2::IComposerClient::Composition::CLIENT,
+              mOutputLayer.getState().hwc->hwcCompositionType);
+}
+
+/*
+ * OutputLayer::prepareForDeviceLayerRequests()
+ */
+
+TEST_F(OutputLayerTest, prepareForDeviceLayerRequestsResetsRequestState) {
+    mOutputLayer.editState().clearClientTarget = true;
+
+    mOutputLayer.prepareForDeviceLayerRequests();
+
+    EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
+}
+
+/*
+ * OutputLayer::applyDeviceLayerRequest()
+ */
+
+TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesClearClientTarget) {
+    mOutputLayer.editState().clearClientTarget = false;
+
+    mOutputLayer.applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET);
+
+    EXPECT_TRUE(mOutputLayer.getState().clearClientTarget);
+}
+
+TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesUnknownRequest) {
+    mOutputLayer.editState().clearClientTarget = false;
+
+    mOutputLayer.applyDeviceLayerRequest(static_cast<Hwc2::IComposerClient::LayerRequest>(0));
+
+    EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 6f087d9..aa35d25 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -17,6 +17,7 @@
 #include <cmath>
 
 #include <compositionengine/impl/Output.h>
+#include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/mock/CompositionEngine.h>
 #include <compositionengine/mock/DisplayColorProfile.h>
 #include <compositionengine/mock/Layer.h>
@@ -37,8 +38,7 @@
 using testing::ReturnRef;
 using testing::StrictMock;
 
-class OutputTest : public testing::Test {
-public:
+struct OutputTest : public testing::Test {
     OutputTest() {
         mOutput.setDisplayColorProfileForTest(
                 std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
@@ -46,7 +46,6 @@
 
         mOutput.editState().bounds = kDefaultDisplaySize;
     }
-    ~OutputTest() override = default;
 
     static const Rect kDefaultDisplaySize;
 
@@ -58,7 +57,7 @@
 
 const Rect OutputTest::kDefaultDisplaySize{100, 200};
 
-/* ------------------------------------------------------------------------
+/*
  * Basic construction
  */
 
@@ -77,7 +76,7 @@
     EXPECT_FALSE(mOutput.isValid());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setCompositionEnabled()
  */
 
@@ -108,7 +107,7 @@
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setProjection()
  */
 
@@ -130,7 +129,7 @@
     EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setBounds()
  */
 
@@ -147,7 +146,7 @@
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setLayerStackFilter()
  */
 
@@ -161,7 +160,7 @@
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setColorTransform
  */
 
@@ -200,7 +199,7 @@
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setColorMode
  */
 
@@ -239,7 +238,7 @@
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::setRenderSurface()
  */
 
@@ -254,7 +253,7 @@
     EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::getDirtyRegion()
  */
 
@@ -283,7 +282,7 @@
     }
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::belongsInOutput()
  */
 
@@ -310,7 +309,7 @@
     EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::getOutputLayerForLayer()
  */
 
@@ -342,7 +341,7 @@
     EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * Output::getOrCreateOutputLayer()
  */
 
@@ -389,5 +388,63 @@
     }
 }
 
+/*
+ * Output::prepareFrame()
+ */
+
+struct OutputPrepareFrameTest : public testing::Test {
+    struct OutputPartialMock : public impl::Output {
+        OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine)
+              : impl::Output(compositionEngine) {}
+
+        // Sets up the helper functions called by prepareFrame to use a mock
+        // implementations.
+        MOCK_METHOD0(chooseCompositionStrategy, void());
+    };
+
+    OutputPrepareFrameTest() {
+        mOutput.setDisplayColorProfileForTest(
+                std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+        mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+    }
+
+    StrictMock<mock::CompositionEngine> mCompositionEngine;
+    mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+    mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+    StrictMock<OutputPartialMock> mOutput{mCompositionEngine};
+};
+
+TEST_F(OutputPrepareFrameTest, takesEarlyOutIfNotEnabled) {
+    mOutput.editState().isEnabled = false;
+
+    mOutput.prepareFrame();
+}
+
+TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurface) {
+    mOutput.editState().isEnabled = true;
+    mOutput.editState().usesClientComposition = false;
+    mOutput.editState().usesDeviceComposition = true;
+
+    EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
+    EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
+
+    mOutput.prepareFrame();
+}
+
+// Note: Use OutputTest and not OutputPrepareFrameTest, so the real
+// base chooseCompositionStrategy() is invoked.
+TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) {
+    mOutput.editState().isEnabled = true;
+    mOutput.editState().usesClientComposition = false;
+    mOutput.editState().usesDeviceComposition = true;
+
+    EXPECT_CALL(*mRenderSurface, prepareFrame(true, false));
+
+    mOutput.prepareFrame();
+
+    EXPECT_TRUE(mOutput.getState().usesClientComposition);
+    EXPECT_FALSE(mOutput.getState().usesDeviceComposition);
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 87419ea..da3f4fb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -18,6 +18,7 @@
 #include <cstdint>
 
 #include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/impl/RenderSurface.h>
 #include <compositionengine/mock/CompositionEngine.h>
 #include <compositionengine/mock/Display.h>
@@ -27,15 +28,9 @@
 #include <gtest/gtest.h>
 #include <renderengine/mock/RenderEngine.h>
 
-#include "MockHWComposer.h"
-
 namespace android::compositionengine {
 namespace {
 
-/* ------------------------------------------------------------------------
- * RenderSurfaceTest
- */
-
 constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
 constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
 constexpr std::optional<DisplayId> DEFAULT_DISPLAY_ID = std::make_optional(DisplayId{123u});
@@ -55,14 +50,11 @@
     RenderSurfaceTest() {
         EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID));
         EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME));
-        EXPECT_CALL(mCompositionEngine, getHwComposer).WillRepeatedly(ReturnRef(mHwComposer));
         EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine));
         EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL))
                 .WillRepeatedly(Return(NO_ERROR));
     }
-    ~RenderSurfaceTest() override = default;
 
-    StrictMock<android::mock::HWComposer> mHwComposer;
     StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
     StrictMock<mock::CompositionEngine> mCompositionEngine;
     StrictMock<mock::Display> mDisplay;
@@ -74,7 +66,7 @@
                                                            mDisplaySurface}};
 };
 
-/* ------------------------------------------------------------------------
+/*
  * Basic construction
  */
 
@@ -82,7 +74,7 @@
     EXPECT_TRUE(mSurface.isValid());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::initialize()
  */
 
@@ -95,7 +87,7 @@
     mSurface.initialize();
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::getSize()
  */
 
@@ -105,7 +97,7 @@
     EXPECT_EQ(expected, mSurface.getSize());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::getClientTargetAcquireFence()
  */
 
@@ -117,7 +109,7 @@
     EXPECT_EQ(fence.get(), mSurface.getClientTargetAcquireFence().get());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::setDisplaySize()
  */
 
@@ -127,7 +119,7 @@
     mSurface.setDisplaySize(ui::Size(640, 480));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::setBufferDataspace()
  */
 
@@ -138,7 +130,7 @@
     mSurface.setBufferDataspace(ui::Dataspace::DISPLAY_P3);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::setProtected()
  */
 
@@ -179,7 +171,7 @@
     EXPECT_FALSE(mSurface.isProtected());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::beginFrame()
  */
 
@@ -189,73 +181,39 @@
     EXPECT_EQ(NO_ERROR, mSurface.beginFrame(true));
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::prepareFrame()
  */
 
-TEST_F(RenderSurfaceTest, prepareFramePassesOutputLayersToHwc) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(INVALID_OPERATION));
-
-    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
-}
-
-TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(INVALID_OPERATION));
-
-    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
-}
-
 TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(NO_ERROR));
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
-            .WillOnce(Return(INVALID_OPERATION));
+            .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
+    mSurface.prepareFrame(true, true);
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(NO_ERROR));
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+    mSurface.prepareFrame(true, false);
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(NO_ERROR));
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+    mSurface.prepareFrame(false, true);
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
-            .WillOnce(Return(NO_ERROR));
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-    EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+    mSurface.prepareFrame(false, false);
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::dequeueBuffer()
  */
 
@@ -272,7 +230,7 @@
     EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::queueBuffer()
  */
 
@@ -280,9 +238,11 @@
     sp<GraphicBuffer> buffer = new GraphicBuffer();
     mSurface.mutableGraphicBufferForTest() = buffer;
 
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-    EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID))
-            .WillOnce(Return(false));
+    impl::OutputCompositionState state;
+    state.usesClientComposition = false;
+    state.flipClientTarget = false;
+
+    EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
 
     mSurface.queueBuffer(base::unique_fd());
@@ -294,7 +254,11 @@
     sp<GraphicBuffer> buffer = new GraphicBuffer();
     mSurface.mutableGraphicBufferForTest() = buffer;
 
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    impl::OutputCompositionState state;
+    state.usesClientComposition = true;
+    state.flipClientTarget = false;
+
+    EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
     EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
             .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
@@ -308,8 +272,11 @@
     sp<GraphicBuffer> buffer = new GraphicBuffer();
     mSurface.mutableGraphicBufferForTest() = buffer;
 
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-    EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    impl::OutputCompositionState state;
+    state.usesClientComposition = false;
+    state.flipClientTarget = true;
+
+    EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
     EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
             .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
@@ -322,8 +289,11 @@
 TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
     sp<GraphicBuffer> buffer = new GraphicBuffer();
 
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-    EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    impl::OutputCompositionState state;
+    state.usesClientComposition = false;
+    state.flipClientTarget = true;
+
+    EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
     EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
             .WillOnce(
                     DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
@@ -340,7 +310,10 @@
     sp<GraphicBuffer> buffer = new GraphicBuffer();
     mSurface.mutableGraphicBufferForTest() = buffer;
 
-    EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+    impl::OutputCompositionState state;
+    state.usesClientComposition = true;
+
+    EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
     EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
             .WillOnce(Return(INVALID_OPERATION));
     EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
@@ -353,7 +326,7 @@
     EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::onPresentDisplayCompleted()
  */
 
@@ -363,7 +336,7 @@
     mSurface.onPresentDisplayCompleted();
 }
 
-/* ------------------------------------------------------------------------
+/*
  * RenderSurface::flip()
  */
 
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 3a5f3fa..d40a38c 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,11 +26,6 @@
 
 ContainerLayer::~ContainerLayer() = default;
 
-bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&, const bool,
-                                        renderengine::LayerSettings&) {
-    return false;
-}
-
 bool ContainerLayer::isVisible() const {
     return false;
 }
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 57267c7..a1607ff 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -34,14 +34,6 @@
     bool canReceiveInput() const override;
 
     bool isCreatedFromMainThread() const override { return true; }
-
-    bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
-
-protected:
-    bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
-                            bool useIdentityTransform, Region& clearRegion,
-                            const bool supportProtectedContent,
-                            renderengine::LayerSettings& layer) override;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1099041..d480f7c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -20,6 +20,8 @@
 #define LOG_TAG "HWComposer"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
+#include "HWComposer.h"
+
 #include <compositionengine/Output.h>
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -29,12 +31,10 @@
 #include <utils/Errors.h>
 #include <utils/Trace.h>
 
-#include "HWComposer.h"
-#include "HWC2.h"
-#include "ComposerHal.h"
-
-#include "../Layer.h"           // needed only for debugging
+#include "../Layer.h" // needed only for debugging
 #include "../SurfaceFlinger.h"
+#include "ComposerHal.h"
+#include "HWC2.h"
 
 #define LOG_HWC_DISPLAY_ERROR(hwcDisplayId, msg) \
     ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
@@ -113,31 +113,6 @@
     return mDisplayData.at(*displayId).hwcDisplay->getCapabilities().count(capability) > 0;
 }
 
-void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) {
-    bool valid = true;
-    switch (from) {
-        case HWC2::Composition::Client:
-            valid = false;
-            break;
-        case HWC2::Composition::Device:
-        case HWC2::Composition::SolidColor:
-            valid = (to == HWC2::Composition::Client);
-            break;
-        case HWC2::Composition::Cursor:
-        case HWC2::Composition::Sideband:
-            valid = (to == HWC2::Composition::Client ||
-                    to == HWC2::Composition::Device);
-            break;
-        default:
-            break;
-    }
-
-    if (!valid) {
-        ALOGE("Invalid layer type change: %s --> %s", to_string(from).c_str(),
-                to_string(to).c_str());
-    }
-}
-
 std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
                                                                HWC2::Connection connection) {
     std::optional<DisplayIdentificationInfo> info;
@@ -399,7 +374,9 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::prepare(DisplayId displayId, const compositionengine::Output& output) {
+status_t HWComposer::getDeviceCompositionChanges(
+        DisplayId displayId, bool frameUsesClientComposition,
+        std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
     ATRACE_CALL();
 
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -419,12 +396,8 @@
     // composition.  When there is client composition, since we haven't
     // rendered to the client target yet, we should not attempt to skip
     // validate.
-    //
-    // displayData.hasClientComposition hasn't been updated for this frame.
-    // The check below is incorrect.  We actually rely on HWC here to fall
-    // back to validate when there is any client layer.
     displayData.validateWasSkipped = false;
-    if (!displayData.hasClientComposition) {
+    if (!frameUsesClientComposition) {
         sp<Fence> outPresentFence;
         uint32_t state = UINT32_MAX;
         error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
@@ -449,58 +422,19 @@
         RETURN_IF_HWC_ERROR_FOR("validate", error, displayId, BAD_INDEX);
     }
 
-    std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes;
+    android::HWComposer::DeviceRequestedChanges::ChangedTypes changedTypes;
     changedTypes.reserve(numTypes);
     error = hwcDisplay->getChangedCompositionTypes(&changedTypes);
     RETURN_IF_HWC_ERROR_FOR("getChangedCompositionTypes", error, displayId, BAD_INDEX);
 
-    displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0);
-    std::unordered_map<HWC2::Layer*, HWC2::LayerRequest> layerRequests;
+    auto displayRequests = static_cast<HWC2::DisplayRequest>(0);
+    android::HWComposer::DeviceRequestedChanges::LayerRequests layerRequests;
     layerRequests.reserve(numRequests);
-    error = hwcDisplay->getRequests(&displayData.displayRequests,
-            &layerRequests);
+    error = hwcDisplay->getRequests(&displayRequests, &layerRequests);
     RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
 
-    displayData.hasClientComposition = false;
-    displayData.hasDeviceComposition = false;
-    for (auto& outputLayer : output.getOutputLayersOrderedByZ()) {
-        auto& state = outputLayer->editState();
-        LOG_FATAL_IF(!state.hwc.);
-        auto hwcLayer = (*state.hwc).hwcLayer;
-
-        if (auto it = changedTypes.find(hwcLayer.get()); it != changedTypes.end()) {
-            auto newCompositionType = it->second;
-            validateChange(static_cast<HWC2::Composition>((*state.hwc).hwcCompositionType),
-                           newCompositionType);
-            (*state.hwc).hwcCompositionType =
-                    static_cast<Hwc2::IComposerClient::Composition>(newCompositionType);
-        }
-
-        switch ((*state.hwc).hwcCompositionType) {
-            case Hwc2::IComposerClient::Composition::CLIENT:
-                displayData.hasClientComposition = true;
-                break;
-            case Hwc2::IComposerClient::Composition::DEVICE:
-            case Hwc2::IComposerClient::Composition::SOLID_COLOR:
-            case Hwc2::IComposerClient::Composition::CURSOR:
-            case Hwc2::IComposerClient::Composition::SIDEBAND:
-                displayData.hasDeviceComposition = true;
-                break;
-            default:
-                break;
-        }
-
-        state.clearClientTarget = false;
-        if (auto it = layerRequests.find(hwcLayer.get()); it != layerRequests.end()) {
-            auto request = it->second;
-            if (request == HWC2::LayerRequest::ClearClientTarget) {
-                state.clearClientTarget = true;
-            } else {
-                LOG_DISPLAY_ERROR(displayId,
-                                  ("Unknown layer request " + to_string(request)).c_str());
-            }
-        }
-    }
+    outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
+                                               std::move(layerRequests)});
 
     error = hwcDisplay->acceptChanges();
     RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
@@ -508,40 +442,6 @@
     return NO_ERROR;
 }
 
-bool HWComposer::hasDeviceComposition(const std::optional<DisplayId>& displayId) const {
-    if (!displayId) {
-        // Displays without a corresponding HWC display are never composed by
-        // the device
-        return false;
-    }
-
-    RETURN_IF_INVALID_DISPLAY(*displayId, false);
-    return mDisplayData.at(*displayId).hasDeviceComposition;
-}
-
-bool HWComposer::hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const {
-    if (!displayId) {
-        // Displays without a corresponding HWC display are never composed by
-        // the device
-        return false;
-    }
-
-    RETURN_IF_INVALID_DISPLAY(*displayId, false);
-    return ((static_cast<uint32_t>(mDisplayData.at(*displayId).displayRequests) &
-             static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0);
-}
-
-bool HWComposer::hasClientComposition(const std::optional<DisplayId>& displayId) const {
-    if (!displayId) {
-        // Displays without a corresponding HWC display are always composed by
-        // the client
-        return true;
-    }
-
-    RETURN_IF_INVALID_DISPLAY(*displayId, true);
-    return mDisplayData.at(*displayId).hasClientComposition;
-}
-
 sp<Fence> HWComposer::getPresentFence(DisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
     return mDisplayData.at(displayId).lastPresentFence;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index de863b8..e87c5c3 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -71,8 +71,26 @@
     // Destroy a previously created layer
     virtual void destroyLayer(DisplayId displayId, HWC2::Layer* layer) = 0;
 
-    // Asks the HAL what it can do
-    virtual status_t prepare(DisplayId displayId, const compositionengine::Output&) = 0;
+    struct DeviceRequestedChanges {
+        using ChangedTypes = std::unordered_map<HWC2::Layer*, HWC2::Composition>;
+        using DisplayRequests = HWC2::DisplayRequest;
+        using LayerRequests = std::unordered_map<HWC2::Layer*, HWC2::LayerRequest>;
+
+        ChangedTypes changedTypes;
+        DisplayRequests displayRequests;
+        LayerRequests layerRequests;
+    };
+
+    // Gets any required composition change requests from the HWC device.
+    //
+    // Note that frameUsesClientComposition must be set correctly based on
+    // whether the current frame appears to use client composition. If it is
+    // false some internal optimizations are allowed to present the display
+    // with fewer handshakes, but this does not work if client composition is
+    // expected.
+    virtual status_t getDeviceCompositionChanges(
+            DisplayId, bool frameUsesClientComposition,
+            std::optional<DeviceRequestedChanges>* outChanges) = 0;
 
     virtual status_t setClientTarget(DisplayId displayId, uint32_t slot,
                                      const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
@@ -93,15 +111,6 @@
     // reset state when an external, non-virtual display is disconnected
     virtual void disconnectDisplay(DisplayId displayId) = 0;
 
-    // does this display have layers handled by HWC
-    virtual bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const = 0;
-
-    // does this display have pending request to flip client target
-    virtual bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const = 0;
-
-    // does this display have layers handled by GLES
-    virtual bool hasClientComposition(const std::optional<DisplayId>& displayId) const = 0;
-
     // get the present fence received from the last call to present.
     virtual sp<Fence> getPresentFence(DisplayId displayId) const = 0;
 
@@ -210,8 +219,9 @@
     // Destroy a previously created layer
     void destroyLayer(DisplayId displayId, HWC2::Layer* layer) override;
 
-    // Asks the HAL what it can do
-    status_t prepare(DisplayId displayId, const compositionengine::Output&) override;
+    status_t getDeviceCompositionChanges(
+            DisplayId, bool frameUsesClientComposition,
+            std::optional<DeviceRequestedChanges>* outChanges) override;
 
     status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
                              const sp<GraphicBuffer>& target, ui::Dataspace dataspace) override;
@@ -231,15 +241,6 @@
     // reset state when an external, non-virtual display is disconnected
     void disconnectDisplay(DisplayId displayId) override;
 
-    // does this display have layers handled by HWC
-    bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const override;
-
-    // does this display have pending request to flip client target
-    bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const override;
-
-    // does this display have layers handled by GLES
-    bool hasClientComposition(const std::optional<DisplayId>& displayId) const override;
-
     // get the present fence received from the last call to present.
     sp<Fence> getPresentFence(DisplayId displayId) const override;
 
@@ -326,14 +327,10 @@
 
     std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
 
-    static void validateChange(HWC2::Composition from, HWC2::Composition to);
-
     struct DisplayData {
         bool isVirtual = false;
-        bool hasClientComposition = false;
-        bool hasDeviceComposition = false;
+
         HWC2::Display* hwcDisplay = nullptr;
-        HWC2::DisplayRequest displayRequests;
         sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
         std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
         buffer_handle_t outbufHandle = nullptr;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b5f0800..a2eeea5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -153,7 +153,6 @@
     mRemoteSyncPoints.clear();
 
     {
-        Mutex::Autolock pendingStateLock(mPendingStateMutex);
         for (State pendingState : mPendingStates) {
             pendingState.barrierLayer_legacy = nullptr;
         }
@@ -459,6 +458,10 @@
     }
 }
 
+bool Layer::onPreComposition(nsecs_t) {
+    return false;
+}
+
 void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState,
                                   bool includeGeometry) const {
     if (includeGeometry) {
@@ -508,54 +511,33 @@
 // drawing...
 // ---------------------------------------------------------------------------
 
-bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
-                               Region& clearRegion, const bool supportProtectedContent,
-                               renderengine::LayerSettings& layer) {
-    return prepareClientLayer(renderArea, clip, false, clearRegion, supportProtectedContent, layer);
-}
+std::optional<renderengine::LayerSettings> Layer::prepareClientComposition(
+        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+    if (!getCompositionLayer()) {
+        return {};
+    }
 
-bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
-                               Region& clearRegion, const bool supportProtectedContent,
-                               renderengine::LayerSettings& layer) {
-    return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform,
-                              clearRegion, supportProtectedContent, layer);
-}
-
-bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
-                               bool useIdentityTransform, Region& /*clearRegion*/,
-                               const bool /*supportProtectedContent*/,
-                               renderengine::LayerSettings& layer) {
     FloatRect bounds = getBounds();
     half alpha = getAlpha();
-    layer.geometry.boundaries = bounds;
-    if (useIdentityTransform) {
-        layer.geometry.positionTransform = mat4();
+    renderengine::LayerSettings layerSettings;
+    layerSettings.geometry.boundaries = bounds;
+    if (targetSettings.useIdentityTransform) {
+        layerSettings.geometry.positionTransform = mat4();
     } else {
-        const ui::Transform transform = getTransform();
-        mat4 m;
-        m[0][0] = transform[0][0];
-        m[0][1] = transform[0][1];
-        m[0][3] = transform[0][2];
-        m[1][0] = transform[1][0];
-        m[1][1] = transform[1][1];
-        m[1][3] = transform[1][2];
-        m[3][0] = transform[2][0];
-        m[3][1] = transform[2][1];
-        m[3][3] = transform[2][2];
-        layer.geometry.positionTransform = m;
+        layerSettings.geometry.positionTransform = getTransform().asMatrix4();
     }
 
     if (hasColorTransform()) {
-        layer.colorTransform = getColorTransform();
+        layerSettings.colorTransform = getColorTransform();
     }
 
     const auto roundedCornerState = getRoundedCornerState();
-    layer.geometry.roundedCornersRadius = roundedCornerState.radius;
-    layer.geometry.roundedCornersCrop = roundedCornerState.cropRect;
+    layerSettings.geometry.roundedCornersRadius = roundedCornerState.radius;
+    layerSettings.geometry.roundedCornersCrop = roundedCornerState.cropRect;
 
-    layer.alpha = alpha;
-    layer.sourceDataspace = mCurrentDataSpace;
-    return true;
+    layerSettings.alpha = alpha;
+    layerSettings.sourceDataspace = mCurrentDataSpace;
+    return layerSettings;
 }
 
 Hwc2::IComposerClient::Composition Layer::getCompositionType(
@@ -853,6 +835,7 @@
 
     // Commit the transaction
     commitTransaction(c);
+    mPendingStatesSnapshot = mPendingStates;
     mCurrentState.callbackHandles = {};
     return flags;
 }
@@ -1820,14 +1803,61 @@
     setTransactionFlags(eTransactionNeeded);
 }
 
-void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet,
-                         uint32_t traceFlags) {
+void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) const {
+    ui::Transform transform = getTransform();
+
+    if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
+        for (const auto& pendingState : mPendingStatesSnapshot) {
+            auto barrierLayer = pendingState.barrierLayer_legacy.promote();
+            if (barrierLayer != nullptr) {
+                BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
+                barrierLayerProto->set_id(barrierLayer->sequence);
+                barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
+            }
+        }
+
+        auto buffer = mActiveBuffer;
+        if (buffer != nullptr) {
+            LayerProtoHelper::writeToProto(buffer,
+                                           [&]() { return layerInfo->mutable_active_buffer(); });
+            LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
+                                           layerInfo->mutable_buffer_transform());
+        }
+        layerInfo->set_invalidate(contentDirty);
+        layerInfo->set_is_protected(isProtected());
+        layerInfo->set_dataspace(
+                dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
+        layerInfo->set_queued_frames(getQueuedFrameCount());
+        layerInfo->set_refresh_pending(isBufferLatched());
+        layerInfo->set_curr_frame(mCurrentFrameNumber);
+        layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
+
+        layerInfo->set_corner_radius(getRoundedCornerState().radius);
+        LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
+        LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
+                                               [&]() { return layerInfo->mutable_position(); });
+        LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
+        LayerProtoHelper::writeToProto(visibleRegion,
+                                       [&]() { return layerInfo->mutable_visible_region(); });
+        LayerProtoHelper::writeToProto(surfaceDamageRegion,
+                                       [&]() { return layerInfo->mutable_damage_region(); });
+    }
+
+    if (traceFlags & SurfaceTracing::TRACE_EXTRA) {
+        LayerProtoHelper::writeToProto(mSourceBounds,
+                                       [&]() { return layerInfo->mutable_source_bounds(); });
+        LayerProtoHelper::writeToProto(mScreenBounds,
+                                       [&]() { return layerInfo->mutable_screen_bounds(); });
+    }
+}
+
+void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+                                    uint32_t traceFlags) const {
     const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
     const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
     const State& state = useDrawing ? mDrawingState : mCurrentState;
 
     ui::Transform requestedTransform = state.active_legacy.transform;
-    ui::Transform transform = getTransform();
 
     if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
         layerInfo->set_id(sequence);
@@ -1847,17 +1877,10 @@
 
         LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
                                        [&]() { return layerInfo->mutable_transparent_region(); });
-        LayerProtoHelper::writeToProto(visibleRegion,
-                                       [&]() { return layerInfo->mutable_visible_region(); });
-        LayerProtoHelper::writeToProto(surfaceDamageRegion,
-                                       [&]() { return layerInfo->mutable_damage_region(); });
 
         layerInfo->set_layer_stack(getLayerStack());
         layerInfo->set_z(state.z);
 
-        LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
-                                               [&]() { return layerInfo->mutable_position(); });
-
         LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(),
                                                [&]() {
                                                    return layerInfo->mutable_requested_position();
@@ -1868,15 +1891,9 @@
 
         LayerProtoHelper::writeToProto(state.crop_legacy,
                                        [&]() { return layerInfo->mutable_crop(); });
-        layerInfo->set_corner_radius(getRoundedCornerState().radius);
 
         layerInfo->set_is_opaque(isOpaque(state));
-        layerInfo->set_invalidate(contentDirty);
-        layerInfo->set_is_protected(isProtected());
 
-        // XXX (b/79210409) mCurrentDataSpace is not protected
-        layerInfo->set_dataspace(
-                dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
 
         layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
         LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
@@ -1884,7 +1901,6 @@
                                        [&]() { return layerInfo->mutable_requested_color(); });
         layerInfo->set_flags(state.flags);
 
-        LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
         LayerProtoHelper::writeToProto(requestedTransform,
                                        layerInfo->mutable_requested_transform());
 
@@ -1901,29 +1917,6 @@
         } else {
             layerInfo->set_z_order_relative_of(-1);
         }
-
-        auto buffer = mActiveBuffer;
-        if (buffer != nullptr) {
-            LayerProtoHelper::writeToProto(buffer,
-                                           [&]() { return layerInfo->mutable_active_buffer(); });
-            LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
-                                           layerInfo->mutable_buffer_transform());
-        }
-
-        layerInfo->set_queued_frames(getQueuedFrameCount());
-        layerInfo->set_refresh_pending(isBufferLatched());
-        layerInfo->set_curr_frame(mCurrentFrameNumber);
-        layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
-
-        for (const auto& pendingState : mPendingStates) {
-            auto barrierLayer = pendingState.barrierLayer_legacy.promote();
-            if (barrierLayer != nullptr) {
-                BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
-                barrierLayerProto->set_id(barrierLayer->sequence);
-                barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
-            }
-        }
-        LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
     }
 
     if (traceFlags & SurfaceTracing::TRACE_INPUT) {
@@ -1936,23 +1929,19 @@
         for (const auto& entry : state.metadata.mMap) {
             (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
         }
-        LayerProtoHelper::writeToProto(mEffectiveTransform,
-                                       layerInfo->mutable_effective_transform());
-        LayerProtoHelper::writeToProto(mSourceBounds,
-                                       [&]() { return layerInfo->mutable_source_bounds(); });
-        LayerProtoHelper::writeToProto(mScreenBounds,
-                                       [&]() { return layerInfo->mutable_screen_bounds(); });
     }
 }
 
-void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
-                         uint32_t traceFlags) {
+void Layer::writeToProtoCompositionState(LayerProto* layerInfo,
+                                         const sp<DisplayDevice>& displayDevice,
+                                         uint32_t traceFlags) const {
     auto outputLayer = findOutputLayerForDisplay(displayDevice);
     if (!outputLayer) {
         return;
     }
 
-    writeToProto(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
+    writeToProtoDrawingState(layerInfo, traceFlags);
+    writeToProtoCommonState(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
 
     const auto& compositionState = outputLayer->getState();
 
@@ -1970,13 +1959,6 @@
             static_cast<int32_t>(compositionState.hwc ? (*compositionState.hwc).hwcCompositionType
                                                       : Hwc2::IComposerClient::Composition::CLIENT);
     layerInfo->set_hwc_composition_type(compositionType);
-
-    if (std::strcmp(getTypeId(), "BufferLayer") == 0 &&
-        static_cast<BufferLayer*>(this)->isProtected()) {
-        layerInfo->set_is_protected(true);
-    } else {
-        layerInfo->set_is_protected(false);
-    }
 }
 
 bool Layer::isRemovedFromCurrentState() const  {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 45199dd..953f25d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -435,11 +435,21 @@
 
     bool isRemovedFromCurrentState() const;
 
-    void writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet,
-                      uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
-
-    void writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
-                      uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
+    // Write states that are modified by the main thread. This includes drawing
+    // state as well as buffer data. This should be called in the main or tracing
+    // thread.
+    void writeToProtoDrawingState(LayerProto* layerInfo,
+                                  uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+    // Write states that are modified by the main thread. This includes drawing
+    // state as well as buffer data and composition data for layers on the specified
+    // display. This should be called in the main or tracing thread.
+    void writeToProtoCompositionState(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
+                                      uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+    // Write drawing or current state. If writing current state, the caller should hold the
+    // external mStateLock. If writing drawing state, this function should be called on the
+    // main or tracing thread.
+    void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+                                 uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
 
     virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
     virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -451,19 +461,17 @@
         return s.activeTransparentRegion_legacy;
     }
     virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
-
-protected:
-    virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
-                                    bool useIdentityTransform, Region& clearRegion,
-                                    const bool supportProtectedContent,
-                                    renderengine::LayerSettings& layer);
+    virtual bool needsFiltering(const sp<const DisplayDevice>&) const { return false; }
 
 public:
     /*
      * compositionengine::LayerFE overrides
      */
+    bool onPreComposition(nsecs_t) override;
     void latchCompositionState(compositionengine::LayerFECompositionState&,
                                bool includeGeometry) const override;
+    std::optional<renderengine::LayerSettings> prepareClientComposition(
+            compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
     void onLayerDisplayed(const sp<Fence>& releaseFence) override;
     const char* getDebugName() const override;
 
@@ -499,17 +507,6 @@
     virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
 
     /*
-     * prepareClientLayer - populates a renderengine::LayerSettings to passed to
-     * RenderEngine::drawLayers. Returns true if the layer can be used, and
-     * false otherwise.
-     */
-    bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion,
-                            const bool supportProtectedContent, renderengine::LayerSettings& layer);
-    bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
-                            Region& clearRegion, const bool supportProtectedContent,
-                            renderengine::LayerSettings& layer);
-
-    /*
      * doTransaction - process the transaction. This is a good place to figure
      * out which attributes of the surface have changed.
      */
@@ -813,13 +810,15 @@
 
     bool mPrimaryDisplayOnly = false;
 
-    // these are protected by an external lock
-    State mCurrentState;
+    // These are only accessed by the main thread or the tracing thread.
     State mDrawingState;
-    std::atomic<uint32_t> mTransactionFlags{0};
+    // Store a copy of the pending state so that the drawing thread can access the
+    // states without a lock.
+    Vector<State> mPendingStatesSnapshot;
 
-    // Accessed from main thread and binder threads
-    Mutex mPendingStateMutex;
+    // these are protected by an external lock (mStateLock)
+    State mCurrentState;
+    std::atomic<uint32_t> mTransactionFlags{0};
     Vector<State> mPendingStates;
 
     // Timestamp history for UIAutomation. Thread safe.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7345e8d..488b9ef 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1790,11 +1790,12 @@
     mCompositionEngine->preComposition(refreshArgs);
     rebuildLayerStacks();
     calculateWorkingSet();
-    for (const auto& [token, display] : mDisplays) {
-        beginFrame(display);
-        prepareFrame(display);
-        doDebugFlashRegions(display, repaintEverything);
-        doComposition(display, repaintEverything);
+    for (const auto& [token, displayDevice] : mDisplays) {
+        auto display = displayDevice->getCompositionDisplay();
+        display->beginFrame();
+        display->prepareFrame();
+        doDebugFlashRegions(displayDevice, repaintEverything);
+        doComposition(displayDevice, repaintEverything);
     }
 
     logLayerStats();
@@ -1802,16 +1803,16 @@
     postFrame();
     postComposition();
 
-    mHadClientComposition = false;
-    mHadDeviceComposition = false;
-    for (const auto& [token, displayDevice] : mDisplays) {
-        auto display = displayDevice->getCompositionDisplay();
-        const auto displayId = display->getId();
-        mHadClientComposition =
-                mHadClientComposition || getHwComposer().hasClientComposition(displayId);
-        mHadDeviceComposition =
-                mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId);
-    }
+    mHadClientComposition =
+            std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
+                auto& displayDevice = tokenDisplayPair.second;
+                return displayDevice->getCompositionDisplay()->getState().usesClientComposition;
+            });
+    mHadDeviceComposition =
+            std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
+                auto& displayDevice = tokenDisplayPair.second;
+                return displayDevice->getCompositionDisplay()->getState().usesDeviceComposition;
+            });
 
     mVSyncModulator->onRefreshed(mHadClientComposition);
 
@@ -1948,13 +1949,13 @@
         }
     }
 
-    postFramebuffer(displayDevice);
+    displayDevice->getCompositionDisplay()->postFramebuffer();
 
     if (mDebugRegion > 1) {
         usleep(mDebugRegion * 1000);
     }
 
-    prepareFrame(displayDevice);
+    displayDevice->getCompositionDisplay()->prepareFrame();
 }
 
 void SurfaceFlinger::logLayerStats() {
@@ -2043,7 +2044,7 @@
 
     getBE().mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
-    if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
+    if (displayDevice && displayDevice->getCompositionDisplay()->getState().usesClientComposition) {
         glCompositionDoneFenceTime =
                 std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
                                                     ->getRenderSurface()
@@ -2373,51 +2374,6 @@
     profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
 }
 
-void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) {
-    auto display = displayDevice->getCompositionDisplay();
-    const auto& displayState = display->getState();
-
-    bool dirty = !display->getDirtyRegion(false).isEmpty();
-    bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
-    bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
-
-    // If nothing has changed (!dirty), don't recompose.
-    // If something changed, but we don't currently have any visible layers,
-    //   and didn't when we last did a composition, then skip it this time.
-    // The second rule does two things:
-    // - When all layers are removed from a display, we'll emit one black
-    //   frame, then nothing more until we get new layers.
-    // - When a display is created with a private layer stack, we won't
-    //   emit any black frames until a layer is added to the layer stack.
-    bool mustRecompose = dirty && !(empty && wasEmpty);
-
-    const char flagPrefix[] = {'-', '+'};
-    static_cast<void>(flagPrefix);
-    ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
-             __FUNCTION__, mustRecompose ? "doing" : "skipping",
-             displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
-             flagPrefix[wasEmpty]);
-
-    display->getRenderSurface()->beginFrame(mustRecompose);
-
-    if (mustRecompose) {
-        display->editState().lastCompositionHadVisibleLayers = !empty;
-    }
-}
-
-void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& displayDevice) {
-    auto display = displayDevice->getCompositionDisplay();
-    const auto& displayState = display->getState();
-
-    if (!displayState.isEnabled) {
-        return;
-    }
-
-    status_t result = display->getRenderSurface()->prepareFrame();
-    ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
-             displayDevice->getDebugName().c_str(), result, strerror(-result));
-}
-
 void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
     ATRACE_CALL();
     ALOGV("doComposition");
@@ -2435,7 +2391,7 @@
         display->editState().dirtyRegion.clear();
         display->getRenderSurface()->flip();
     }
-    postFramebuffer(displayDevice);
+    displayDevice->getCompositionDisplay()->postFramebuffer();
 }
 
 void SurfaceFlinger::postFrame()
@@ -2450,68 +2406,6 @@
     }
 }
 
-void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& displayDevice) {
-    ATRACE_CALL();
-    ALOGV("postFramebuffer");
-
-    auto display = displayDevice->getCompositionDisplay();
-    const auto& displayState = display->getState();
-    const auto displayId = display->getId();
-
-    if (displayState.isEnabled) {
-        if (displayId) {
-            getHwComposer().presentAndGetReleaseFences(*displayId);
-        }
-        display->getRenderSurface()->onPresentDisplayCompleted();
-        for (auto& layer : display->getOutputLayersOrderedByZ()) {
-            sp<Fence> releaseFence = Fence::NO_FENCE;
-            bool usedClientComposition = true;
-
-            // The layer buffer from the previous frame (if any) is released
-            // by HWC only when the release fence from this frame (if any) is
-            // signaled.  Always get the release fence from HWC first.
-            if (layer->getState().hwc) {
-                const auto& hwcState = *layer->getState().hwc;
-                releaseFence =
-                        getHwComposer().getLayerReleaseFence(*displayId, hwcState.hwcLayer.get());
-                usedClientComposition =
-                        hwcState.hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
-            }
-
-            // If the layer was client composited in the previous frame, we
-            // need to merge with the previous client target acquire fence.
-            // Since we do not track that, always merge with the current
-            // client target acquire fence when it is available, even though
-            // this is suboptimal.
-            if (usedClientComposition) {
-                releaseFence =
-                        Fence::merge("LayerRelease", releaseFence,
-                                     display->getRenderSurface()->getClientTargetAcquireFence());
-            }
-
-            layer->getLayerFE().onLayerDisplayed(releaseFence);
-        }
-
-        // We've got a list of layers needing fences, that are disjoint with
-        // display->getVisibleLayersSortedByZ.  The best we can do is to
-        // supply them with the present fence.
-        auto releasedLayers = display->takeReleasedLayers();
-        if (!releasedLayers.empty()) {
-            sp<Fence> presentFence =
-                    displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
-            for (auto& weakLayer : releasedLayers) {
-                if (auto layer = weakLayer.promote(); layer != nullptr) {
-                    layer->onLayerDisplayed(presentFence);
-                }
-            }
-        }
-
-        if (displayId) {
-            getHwComposer().clearReleaseFences(*displayId);
-        }
-    }
-}
-
 void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
 {
     ATRACE_CALL();
@@ -3354,9 +3248,7 @@
     const Region bounds(displayState.bounds);
     const DisplayRenderArea renderArea(displayDevice);
     const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
-                                                      getHwComposer().hasClientComposition(
-                                                              displayId)};
-
+                                                      displayState.usesClientComposition};
     bool applyColorMatrix = false;
 
     renderengine::DisplaySettings clientCompositionDisplay;
@@ -3409,7 +3301,7 @@
         clientCompositionDisplay.maxLuminance =
                 profile->getHdrCapabilities().getDesiredMaxLuminance();
 
-        const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
+        const bool hasDeviceComposition = displayState.usesDeviceComposition;
         const bool skipClientColorTransform =
                 getHwComposer()
                         .hasDisplayCapability(displayId,
@@ -3427,6 +3319,7 @@
      */
 
     ALOGV("Rendering client layers");
+    const bool useIdentityTransform = false;
     bool firstLayer = true;
     Region clearRegion = Region::INVALID_REGION;
     for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
@@ -3447,13 +3340,20 @@
                         layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
                         // never clear the very first layer since we're
                         // guaranteed the FB is already cleared
-                        renderengine::LayerSettings layerSettings;
                         Region dummyRegion;
-                        bool prepared =
-                                layer->prepareClientLayer(renderArea, clip, dummyRegion,
-                                                          supportProtectedContent, layerSettings);
+                        compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+                                clip,
+                                useIdentityTransform,
+                                layer->needsFiltering(renderArea.getDisplayDevice()) ||
+                                        renderArea.needsFiltering(),
+                                renderArea.isSecure(),
+                                supportProtectedContent,
+                                dummyRegion,
+                        };
+                        auto result = layer->prepareClientComposition(targetSettings);
 
-                        if (prepared) {
+                        if (result) {
+                            auto& layerSettings = *result;
                             layerSettings.source.buffer.buffer = nullptr;
                             layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
                             layerSettings.alpha = half(0.0);
@@ -3464,12 +3364,18 @@
                     break;
                 }
                 case Hwc2::IComposerClient::Composition::CLIENT: {
-                    renderengine::LayerSettings layerSettings;
-                    bool prepared =
-                            layer->prepareClientLayer(renderArea, clip, clearRegion,
-                                                      supportProtectedContent, layerSettings);
-                    if (prepared) {
-                        clientCompositionLayers.push_back(layerSettings);
+                    compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+                            clip,
+                            useIdentityTransform,
+                            layer->needsFiltering(renderArea.getDisplayDevice()) ||
+                                    renderArea.needsFiltering(),
+                            renderArea.isSecure(),
+                            supportProtectedContent,
+                            clearRegion,
+                    };
+                    auto result = layer->prepareClientComposition(targetSettings);
+                    if (result) {
+                        clientCompositionLayers.push_back(*result);
                     }
                     break;
                 }
@@ -4051,15 +3957,6 @@
         // We don't trigger a traversal here because if no other state is
         // changed, we don't want this to cause any more work
     }
-    if (what & layer_state_t::eReparent) {
-        bool hadParent = layer->hasParent();
-        if (layer->reparent(s.parentHandleForChild)) {
-            if (!hadParent) {
-                mCurrentState.layersSortedByZ.remove(layer);
-            }
-            flags |= eTransactionNeeded|eTraversalNeeded;
-        }
-    }
     if (what & layer_state_t::eReparentChildren) {
         if (layer->reparentChildren(s.reparentHandle)) {
             flags |= eTransactionNeeded|eTraversalNeeded;
@@ -4120,6 +4017,19 @@
             flags |= eTraversalNeeded;
         }
     }
+    // This has to happen after we reparent children because when we reparent to null we remove
+    // child layers from current state and remove its relative z. If the children are reparented in
+    // the same transaction, then we have to make sure we reparent the children first so we do not
+    // lose its relative z order.
+    if (what & layer_state_t::eReparent) {
+        bool hadParent = layer->hasParent();
+        if (layer->reparent(s.parentHandleForChild)) {
+            if (!hadParent) {
+                mCurrentState.layersSortedByZ.remove(layer);
+            }
+            flags |= eTransactionNeeded | eTraversalNeeded;
+        }
+    }
     std::vector<sp<CallbackHandle>> callbackHandles;
     if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) {
         for (const auto& [listener, callbackIds] : listenerCallbacks) {
@@ -4577,18 +4487,22 @@
 
         if (const auto it = dumpers.find(flag); it != dumpers.end()) {
             (it->second)(args, asProto, result);
-        } else {
-            if (asProto) {
-                LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
-                result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
-            } else {
-                dumpAllLocked(args, result);
-            }
+        } else if (!asProto) {
+            dumpAllLocked(args, result);
         }
 
         if (locked) {
             mStateLock.unlock();
         }
+
+        LayersProto layersProto = dumpProtoFromMainThread();
+        if (asProto) {
+            result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
+        } else {
+            auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+            result.append(LayerProtoParser::layerTreeToString(layerTree));
+            result.append("\n");
+        }
     }
     write(fd, result.c_str(), result.size());
     return NO_ERROR;
@@ -4829,19 +4743,23 @@
     result.append("\n");
 }
 
-LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet,
-                                          uint32_t traceFlags) const {
+LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
     LayersProto layersProto;
-    const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
-    const State& state = useDrawing ? mDrawingState : mCurrentState;
-    state.traverseInZOrder([&](Layer* layer) {
+    mDrawingState.traverseInZOrder([&](Layer* layer) {
         LayerProto* layerProto = layersProto.add_layers();
-        layer->writeToProto(layerProto, stateSet, traceFlags);
+        layer->writeToProtoDrawingState(layerProto, traceFlags);
+        layer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
     });
 
     return layersProto;
 }
 
+LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
+    LayersProto layersProto;
+    postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); }));
+    return layersProto;
+}
+
 LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(
         const sp<DisplayDevice>& displayDevice) const {
     LayersProto layersProto;
@@ -4862,7 +4780,7 @@
     mDrawingState.traverseInZOrder([&](Layer* layer) {
         if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) {
             LayerProto* layerProto = layersProto.add_layers();
-            layer->writeToProto(layerProto, displayDevice);
+            layer->writeToProtoCompositionState(layerProto, displayDevice);
         }
     });
 
@@ -4927,13 +4845,6 @@
     colorizer.reset(result);
 
     {
-        LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
-        auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
-        result.append(LayerProtoParser::layerTreeToString(layerTree));
-        result.append("\n");
-    }
-
-    {
         StringAppendF(&result, "Composition layers\n");
         mDrawingState.traverseInZOrder([&](Layer* layer) {
             auto compositionLayer = layer->getCompositionLayer();
@@ -5049,19 +4960,6 @@
     result.append("\n");
 }
 
-const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
-    // Note: mStateLock is held here
-    for (const auto& [token, display] : mDisplays) {
-        if (display->getId() == displayId) {
-            return getDisplayDeviceLocked(token)->getVisibleLayersSortedByZ();
-        }
-    }
-
-    ALOGE("%s: Invalid display %s", __FUNCTION__, to_string(displayId).c_str());
-    static const Vector<sp<Layer>> empty;
-    return empty;
-}
-
 void SurfaceFlinger::updateColorMatrixLocked() {
     mat4 colorMatrix;
     if (mGlobalSaturationFactor != 1.0f) {
@@ -6022,11 +5920,19 @@
 
     Region clearRegion = Region::INVALID_REGION;
     traverseLayers([&](Layer* layer) {
-        renderengine::LayerSettings layerSettings;
-        bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
-                                                  false, layerSettings);
-        if (prepared) {
-            clientCompositionLayers.push_back(layerSettings);
+        const bool supportProtectedContent = false;
+        Region clip(renderArea.getBounds());
+        compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+                clip,
+                useIdentityTransform,
+                layer->needsFiltering(renderArea.getDisplayDevice()) || renderArea.needsFiltering(),
+                renderArea.isSecure(),
+                supportProtectedContent,
+                clearRegion,
+        };
+        auto result = layer->prepareClientComposition(targetSettings);
+        if (result) {
+            clientCompositionLayers.push_back(*result);
         }
     });
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 04e0c89..3974a8c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -265,7 +265,8 @@
     status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
 
     // post a synchronous message to the main thread
-    status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
+    status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0)
+            EXCLUDES(mStateLock);
 
     // force full composition on all displays
     void repaintEverything();
@@ -304,10 +305,6 @@
     // TODO: this should be made accessible only to MessageQueue
     void onMessageReceived(int32_t what);
 
-    // for debugging only
-    // TODO: this should be made accessible only to HWComposer
-    const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
-
     renderengine::RenderEngine& getRenderEngine() const;
 
     bool authenticateSurfaceTextureLocked(
@@ -763,17 +760,6 @@
                        ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const;
 
     void calculateWorkingSet();
-    /*
-     * beginFrame - This function handles any pre-frame processing that needs to be
-     * prior to any CompositionInfo handling and is not dependent on data in
-     * CompositionInfo
-     */
-    void beginFrame(const sp<DisplayDevice>& display);
-    /* prepareFrame - This function will call into the DisplayDevice to prepare a
-     * frame after CompositionInfo has been programmed.   This provides a mechanism
-     * to prepare the hardware composer
-     */
-    void prepareFrame(const sp<DisplayDevice>& display);
     void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
     void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
     void logLayerStats();
@@ -785,7 +771,6 @@
     bool doComposeSurfaces(const sp<DisplayDevice>& display, const Region& debugRegionm,
                            base::unique_fd* readyFence);
 
-    void postFramebuffer(const sp<DisplayDevice>& display);
     void postFrame();
 
     /* ------------------------------------------------------------------------
@@ -895,8 +880,9 @@
     void dumpBufferingStats(std::string& result) const;
     void dumpDisplayIdentificationData(std::string& result) const;
     void dumpWideColorInfo(std::string& result) const;
-    LayersProto dumpProtoInfo(LayerVector::StateSet stateSet,
-                              uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+    LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+    LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL)
+            EXCLUDES(mStateLock);
     void withTracingLock(std::function<void()> operation) REQUIRES(mStateLock);
     LayersProto dumpVisibleLayersProtoInfo(const sp<DisplayDevice>& display) const;
 
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index fdc6c58..6858c4d 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -46,7 +46,7 @@
 using Increment = surfaceflinger::Increment;
 using DisplayChange = surfaceflinger::DisplayChange;
 
-constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
 
 class SurfaceInterceptor {
 public:
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index c4ab066..9053f2c 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -162,7 +162,7 @@
     LayersTraceProto entry;
     entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
     entry.set_where(where);
-    LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing, mTraceFlags));
+    LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
     entry.mutable_layers()->Swap(&layers);
 
     return entry;
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index bc5f1aa..59e9c00 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -60,7 +60,7 @@
 constexpr auto LAYER_NAME = "Layer Create and Delete Test";
 constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
 
-constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
 
 // Fill an RGBA_8888 formatted surface with a single color.
 static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) {
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index c8f5618..b1fde22 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -4686,6 +4686,34 @@
     }
 }
 
+TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) {
+    sp<SurfaceControl> mGrandChild =
+            createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+    fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+    // draw grand child behind the foreground surface
+    asTransaction([&](Transaction& t) {
+        t.setRelativeLayer(mGrandChild, mFGSurfaceControl->getHandle(), -1);
+    });
+
+    {
+        SCOPED_TRACE("Child visible");
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->checkPixel(64, 64, 200, 200, 200);
+    }
+
+    asTransaction([&](Transaction& t) {
+        t.reparent(mChild, nullptr);
+        t.reparentChildren(mChild, mFGSurfaceControl->getHandle());
+    });
+
+    {
+        SCOPED_TRACE("foreground visible reparenting grandchild");
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->checkPixel(64, 64, 195, 63, 63);
+    }
+}
+
 TEST_F(ChildLayerTest, DetachChildrenSameClient) {
     asTransaction([&](Transaction& t) {
         t.show(mChild);
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 0f21ad8..47243a9 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -296,7 +296,6 @@
         EXPECT_CALL(*test->mComposer,
                     setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
                 .Times(1);
-        EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
         EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1);
         EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1);
         EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
@@ -336,11 +335,21 @@
     }
 
     static void setupHwcCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+
         EXPECT_CALL(*test->mDisplaySurface,
                     prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC))
                 .Times(1);
     }
 
+    static void setupHwcClientCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+    }
+
+    static void setupHwcForcedClientCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, validateDisplay(HWC_DISPLAY, _, _)).Times(1);
+    }
+
     static void setupRECompositionCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mDisplaySurface,
                     prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GLES))
@@ -414,6 +423,8 @@
     }
 
     static void setupHwcCompositionCallExpectations(CompositionTest*) {}
+    static void setupHwcClientCompositionCallExpectations(CompositionTest*) {}
+    static void setupHwcForcedClientCompositionCallExpectations(CompositionTest*) {}
 
     static void setupRECompositionCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
@@ -981,12 +992,13 @@
     template <typename Case>
     static void setupCallExpectations(CompositionTest* test) {
         Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcClientCompositionCallExpectations(test);
         Case::Display::setupRECompositionCallExpectations(test);
         Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
     }
 };
 
-struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
+struct ForcedClientCompositionResultVariant : public CompositionResultBaseVariant {
     static void setupLayerState(CompositionTest* test, sp<Layer> layer) {
         const auto outputLayer = layer->findOutputLayerForDisplay(test->mDisplay);
         LOG_FATAL_IF(!outputLayer);
@@ -994,6 +1006,14 @@
     }
 
     template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcForcedClientCompositionCallExpectations(test);
+        Case::Display::setupRECompositionCallExpectations(test);
+        Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
+    }
+
+    template <typename Case>
     static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
 
     template <typename Case>
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 993b751..85ef475 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -75,6 +75,7 @@
 
     header_libs: [
         "hwvulkan_headers",
+        "libnativeloader-dummy-headers",
         "vulkan_headers",
     ],
     export_header_lib_headers: ["vulkan_headers"],
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index f596086..9a670f6 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -30,6 +30,7 @@
 #include <cutils/properties.h>
 #include <graphicsenv/GraphicsEnv.h>
 #include <log/log.h>
+#include <nativeloader/dlext_namespaces.h>
 #include <sys/prctl.h>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
@@ -44,11 +45,6 @@
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 
-// TODO(b/37049319) Get this from a header once one exists
-extern "C" {
-android_namespace_t* android_get_exported_namespace(const char*);
-}
-
 // #define ENABLE_ALLOC_CALLSTACKS 1
 #if ENABLE_ALLOC_CALLSTACKS
 #include <utils/CallStack.h>