Merge changes from topic "move-vulkan-headers" into qt-dev

* changes:
  Use upstream Vulkan headers from external/vulkan-headers
  Prepare for moving Vulkan headers
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 66c9cc6..7c58a85 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -33,6 +33,8 @@
     chmod 0666 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
     chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_pi_setprio/enable
     chmod 0666 /sys/kernel/tracing/events/sched/sched_pi_setprio/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_waking/enable
+    chmod 0666 /sys/kernel/tracing/events/sched/sched_waking/enable
     chmod 0666 /sys/kernel/debug/tracing/events/cgroup/enable
     chmod 0666 /sys/kernel/tracing/events/cgroup/enable
     chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
diff --git a/include/android/font.h b/include/android/font.h
index 7e5a945..435a573 100644
--- a/include/android/font.h
+++ b/include/android/font.h
@@ -15,6 +15,11 @@
  */
 
 /**
+ * @addtogroup Font
+ * {
+ */
+
+/**
  * @file font.h
  * @brief Provides some constants used in system_fonts.h or fonts_matcher.h
  *
@@ -279,3 +284,5 @@
 __END_DECLS
 
 #endif // ANDROID_FONT_H
+
+/** @} */
diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h
index ad5a4da..e286a4c 100644
--- a/include/android/font_matcher.h
+++ b/include/android/font_matcher.h
@@ -15,6 +15,11 @@
  */
 
 /**
+ * @addtogroup Font
+ * {
+ */
+
+/**
  * @file font_matcher.h
  * @brief Provides the font matching logic with various inputs.
  *
@@ -205,3 +210,5 @@
 __END_DECLS
 
 #endif // ANDROID_FONT_MATCHER_H
+
+/** @} */
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
index 3facf82..dde9055 100644
--- a/include/android/system_fonts.h
+++ b/include/android/system_fonts.h
@@ -15,6 +15,11 @@
  */
 
 /**
+ * @addtogroup Font
+ * {
+ */
+
+/**
  * @file system_fonts.h
  * @brief Provides the system font configurations.
  *
@@ -122,3 +127,5 @@
 __END_DECLS
 
 #endif // ANDROID_SYSTEM_FONTS_H
+
+/** @} */
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index a3165dd..a8b1a4c 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -69,7 +69,7 @@
                                      const sp<IBinder>& applyToken,
                                      const InputWindowCommands& commands,
                                      int64_t desiredPresentTime,
-                                     const cached_buffer_t& uncacheBuffer,
+                                     const client_cache_t& uncacheBuffer,
                                      const std::vector<ListenerCallbacks>& listenerCallbacks) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -88,8 +88,8 @@
         data.writeStrongBinder(applyToken);
         commands.write(data);
         data.writeInt64(desiredPresentTime);
-        data.writeStrongBinder(uncacheBuffer.token);
-        data.writeUint64(uncacheBuffer.cacheId);
+        data.writeWeakBinder(uncacheBuffer.token);
+        data.writeUint64(uncacheBuffer.id);
 
         if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) {
             for (const auto& [listener, callbackIds] : listenerCallbacks) {
@@ -991,9 +991,9 @@
 
             int64_t desiredPresentTime = data.readInt64();
 
-            cached_buffer_t uncachedBuffer;
-            uncachedBuffer.token = data.readStrongBinder();
-            uncachedBuffer.cacheId = data.readUint64();
+            client_cache_t uncachedBuffer;
+            uncachedBuffer.token = data.readWeakBinder();
+            uncachedBuffer.id = data.readUint64();
 
             std::vector<ListenerCallbacks> listenerCallbacks;
             int32_t listenersSize = data.readInt32();
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 3077b21..075bb52 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -87,8 +87,8 @@
            colorTransform.asArray(), 16 * sizeof(float));
     output.writeFloat(cornerRadius);
     output.writeBool(hasListenerCallbacks);
-    output.writeStrongBinder(cachedBuffer.token);
-    output.writeUint64(cachedBuffer.cacheId);
+    output.writeWeakBinder(cachedBuffer.token);
+    output.writeUint64(cachedBuffer.id);
     output.writeParcelable(metadata);
 
     output.writeFloat(bgColorAlpha);
@@ -157,8 +157,8 @@
     colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
     cornerRadius = input.readFloat();
     hasListenerCallbacks = input.readBool();
-    cachedBuffer.token = input.readStrongBinder();
-    cachedBuffer.cacheId = input.readUint64();
+    cachedBuffer.token = input.readWeakBinder();
+    cachedBuffer.id = input.readUint64();
     input.readParcelable(&metadata);
 
     bgColorAlpha = input.readFloat();
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 611da89..2083a2b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -381,17 +381,19 @@
     s.state.parentHandleForChild = nullptr;
 
     composerStates.add(s);
-    sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1, {}, {});
+    sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, {});
 }
 
 void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
 
-    cached_buffer_t uncacheBuffer;
+    client_cache_t uncacheBuffer;
     uncacheBuffer.token = BufferCache::getInstance().getToken();
-    uncacheBuffer.cacheId = cacheId;
+    uncacheBuffer.id = cacheId;
 
-    sf->setTransactionState({}, {}, 0, nullptr, {}, -1, uncacheBuffer, {});
+    sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    sf->setTransactionState({}, {}, 0, applyToken, {}, -1, uncacheBuffer, {});
 }
 
 void SurfaceComposerClient::Transaction::cacheBuffers() {
@@ -422,7 +424,7 @@
         }
         s->what |= layer_state_t::eCachedBufferChanged;
         s->cachedBuffer.token = BufferCache::getInstance().getToken();
-        s->cachedBuffer.cacheId = cacheId;
+        s->cachedBuffer.id = cacheId;
 
         // If we have more buffers than the size of the cache, we should stop caching so we don't
         // evict other buffers in this transaction
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 415b2d5..e8c7a39 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -44,7 +44,7 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-struct cached_buffer_t;
+struct client_cache_t;
 struct ComposerState;
 struct DisplayState;
 struct DisplayInfo;
@@ -137,7 +137,7 @@
                                      const sp<IBinder>& applyToken,
                                      const InputWindowCommands& inputWindowCommands,
                                      int64_t desiredPresentTime,
-                                     const cached_buffer_t& uncacheBuffer,
+                                     const client_cache_t& uncacheBuffer,
                                      const std::vector<ListenerCallbacks>& listenerCallbacks) = 0;
 
     /* signal that we're done booting.
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 2256497..f438eb3 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -40,9 +40,13 @@
 class Parcel;
 class ISurfaceComposerClient;
 
-struct cached_buffer_t {
-    sp<IBinder> token = nullptr;
-    uint64_t cacheId;
+struct client_cache_t {
+    wp<IBinder> token = nullptr;
+    uint64_t id;
+
+    bool operator==(const client_cache_t& other) const { return id == other.id; }
+
+    bool isValid() const { return token != nullptr; }
 };
 
 /*
@@ -187,7 +191,7 @@
     InputWindowInfo inputInfo;
 #endif
 
-    cached_buffer_t cachedBuffer;
+    client_cache_t cachedBuffer;
 
     LayerMetadata metadata;
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index d5bdd74..014b1fa 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -561,8 +561,7 @@
                              const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
                              const sp<IBinder>& /*applyToken*/,
                              const InputWindowCommands& /*inputWindowCommands*/,
-                             int64_t /*desiredPresentTime*/,
-                             const cached_buffer_t& /*cachedBuffer*/,
+                             int64_t /*desiredPresentTime*/, const client_cache_t& /*cachedBuffer*/,
                              const std::vector<ListenerCallbacks>& /*listenerCallbacks*/) override {
     }
 
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 259242b..c1805be 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -360,42 +360,70 @@
     }
 }
 
+static void* attempt_to_load_emulation_driver(const char* kind) {
+    const int emulationStatus = checkGlesEmulationStatus();
+
+    // Invalid emulation status, abort.
+    if (emulationStatus < 0 || emulationStatus > 2) {
+        return nullptr;
+    }
+
+    std::string absolutePath;
+    switch (emulationStatus) {
+        case 0:
+#if defined(__LP64__)
+            absolutePath = "/vendor/lib64/egl/libGLES_android.so";
+#else
+            absolutePath = "/vendor/lib/egl/libGLES_android.so";
+#endif
+            break;
+        case 1:
+            // Use host-side OpenGL through the "emulation" library
+#if defined(__LP64__)
+            absolutePath = std::string("/vendor/lib64/egl/lib") + kind + "_emulation.so";
+#else
+            absolutePath = std::string("/vendor/lib/egl/lib") + kind + "_emulation.so";
+#endif
+            break;
+        case 2:
+            // Use guest side swiftshader library
+#if defined(__LP64__)
+            absolutePath = std::string("/vendor/lib64/egl/lib") + kind + "_swiftshader.so";
+#else
+            absolutePath = std::string("/vendor/lib/egl/lib") + kind + "_swiftshader.so";
+#endif
+            break;
+      default:
+            // Not in emulator, or use other guest-side implementation
+            break;
+    }
+    if (absolutePath.empty()) {
+        // this happens often, we don't want to log an error
+        return nullptr;
+    }
+    const char* const driver_absolute_path = absolutePath.c_str();
+
+    // Try to load drivers from the 'sphal' namespace, if it exist. Fall back to
+    // the original routine when the namespace does not exist.
+    // See /system/core/rootdir/etc/ld.config.txt for the configuration of the
+    // sphal namespace.
+    void* dso = do_android_load_sphal_library(driver_absolute_path,
+                                              RTLD_NOW | RTLD_LOCAL);
+    if (dso == nullptr) {
+        const char* err = dlerror();
+        ALOGE("load_driver(%s): %s", driver_absolute_path, err ? err : "unknown");
+        return nullptr;
+    }
+    ALOGD("loaded %s", driver_absolute_path);
+    return dso;
+}
+
 static void* load_system_driver(const char* kind) {
     ATRACE_CALL();
     class MatchFile {
     public:
         static std::string find(const char* kind) {
             std::string result;
-            int emulationStatus = checkGlesEmulationStatus();
-            switch (emulationStatus) {
-                case 0:
-#if defined(__LP64__)
-                    result = "/vendor/lib64/egl/libGLES_android.so";
-#else
-                    result = "/vendor/lib/egl/libGLES_android.so";
-#endif
-                    return result;
-                case 1:
-                    // Use host-side OpenGL through the "emulation" library
-#if defined(__LP64__)
-                    result = std::string("/vendor/lib64/egl/lib") + kind + "_emulation.so";
-#else
-                    result = std::string("/vendor/lib/egl/lib") + kind + "_emulation.so";
-#endif
-                    return result;
-                case 2:
-                    // Use guest side swiftshader library
-#if defined(__LP64__)
-                    result = std::string("/vendor/lib64/egl/lib") + kind + "_swiftshader.so";
-#else
-                    result = std::string("/vendor/lib/egl/lib") + kind + "_swiftshader.so";
-#endif
-                    return result;
-                default:
-                    // Not in emulator, or use other guest-side implementation
-                    break;
-            }
-
             std::string pattern = std::string("lib") + kind;
             const char* const searchPaths[] = {
 #if defined(__LP64__)
@@ -608,24 +636,39 @@
     if (ns) {
         android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::ANGLE);
         dso = load_angle(kind, ns, cnx);
+        if (dso) {
+            initialize_api(dso, cnx, mask);
+            return dso;
+        }
     }
 #ifndef __ANDROID_VNDK__
-    if (!dso) {
-        android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
-        if (ns) {
-            android::GraphicsEnv::getInstance().setDriverToLoad(
-                    android::GraphicsEnv::Driver::GL_UPDATED);
-            dso = load_updated_driver(kind, ns);
+    ns = android::GraphicsEnv::getInstance().getDriverNamespace();
+    if (ns) {
+        android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL_UPDATED);
+        dso = load_updated_driver(kind, ns);
+        if (dso) {
+            initialize_api(dso, cnx, mask);
+            return dso;
         }
     }
 #endif
-    if (!dso) {
-        android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL);
-        dso = load_system_driver(kind);
-        if (!dso)
-            return nullptr;
+    android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL);
+    dso = attempt_to_load_emulation_driver(kind);
+    if (dso) {
+        initialize_api(dso, cnx, mask);
+        return dso;
     }
 
+    dso = load_system_driver(kind);
+    if (dso) {
+        initialize_api(dso, cnx, mask);
+        return dso;
+    }
+
+    return nullptr;
+}
+
+void Loader::initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask) {
     if (mask & EGL) {
         getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
 
@@ -665,8 +708,6 @@
                 &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
             getProcAddress);
     }
-
-    return dso;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 392887d..083c84e 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -56,6 +56,7 @@
 private:
     Loader();
     void *load_driver(const char* kind, egl_connection_t* cnx, uint32_t mask);
+    void initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask);
 
     static __attribute__((noinline))
     void init_api(void* dso,
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 9080d29..4cd0a13 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -116,7 +116,7 @@
         "BufferLayerConsumer.cpp",
         "BufferQueueLayer.cpp",
         "BufferStateLayer.cpp",
-        "BufferStateLayerCache.cpp",
+        "ClientCache.cpp",
         "Client.cpp",
         "ColorLayer.cpp",
         "ContainerLayer.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index a08ae8c..4ea587d 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -321,7 +321,10 @@
     }
 
     error = hwcLayer->setColorTransform(getColorTransform());
-    if (error != HWC2::Error::None) {
+    if (error == HWC2::Error::Unsupported) {
+        // If per layer color transform is not supported, we use GPU composition.
+        setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CLIENT);
+    } else if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
                 to_string(error).c_str(), static_cast<int32_t>(error));
     }
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 2cbb917..6ef4518 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -26,6 +26,7 @@
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/LayerCompositionState.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <gui/BufferQueue.h>
 #include <private/gui/SyncFeatures.h>
 #include <renderengine/Image.h>
 
@@ -44,7 +45,8 @@
 };
 // clang-format on
 
-BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) : BufferLayer(args) {
+BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args)
+      : BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) {
     mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
     mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
 }
@@ -210,12 +212,13 @@
 }
 
 bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime,
-                                 nsecs_t desiredPresentTime) {
+                                 nsecs_t desiredPresentTime, const client_cache_t& clientCacheId) {
     if (mCurrentState.buffer) {
         mReleasePreviousBuffer = true;
     }
 
     mCurrentState.buffer = buffer;
+    mCurrentState.clientCacheId = clientCacheId;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
 
@@ -589,8 +592,8 @@
 
     uint32_t hwcSlot;
     sp<GraphicBuffer> buffer;
-    hwcInfo.hwcBufferCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, s.buffer, &hwcSlot,
-                                        &buffer);
+    hwcInfo.hwcBufferCache.getHwcBuffer(mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId),
+                                        s.buffer, &hwcSlot, &buffer);
 
     auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
     if (error != HWC2::Error::None) {
@@ -609,4 +612,76 @@
     }
 }
 
+void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
+    std::lock_guard lock(mMutex);
+    if (!clientCacheId.isValid()) {
+        ALOGE("invalid process, failed to erase buffer");
+        return;
+    }
+    eraseBufferLocked(clientCacheId);
+}
+
+uint32_t BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    auto itr = mCachedBuffers.find(clientCacheId);
+    if (itr == mCachedBuffers.end()) {
+        return addCachedBuffer(clientCacheId);
+    }
+    auto& [hwcCacheSlot, counter] = itr->second;
+    counter = mCounter++;
+    return hwcCacheSlot;
+}
+
+uint32_t BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId)
+        REQUIRES(mMutex) {
+    if (!clientCacheId.isValid()) {
+        ALOGE("invalid process, returning invalid slot");
+        return BufferQueue::INVALID_BUFFER_SLOT;
+    }
+
+    ClientCache::getInstance().registerErasedRecipient(clientCacheId, wp<ErasedRecipient>(this));
+
+    uint32_t hwcCacheSlot = getFreeHwcCacheSlot();
+    mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++};
+    return hwcCacheSlot;
+}
+
+uint32_t BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) {
+    if (mFreeHwcCacheSlots.empty()) {
+        evictLeastRecentlyUsed();
+    }
+
+    uint32_t hwcCacheSlot = mFreeHwcCacheSlots.top();
+    mFreeHwcCacheSlots.pop();
+    return hwcCacheSlot;
+}
+
+void BufferStateLayer::HwcSlotGenerator::evictLeastRecentlyUsed() REQUIRES(mMutex) {
+    uint64_t minCounter = UINT_MAX;
+    client_cache_t minClientCacheId = {};
+    for (const auto& [clientCacheId, slotCounter] : mCachedBuffers) {
+        const auto& [hwcCacheSlot, counter] = slotCounter;
+        if (counter < minCounter) {
+            minCounter = counter;
+            minClientCacheId = clientCacheId;
+        }
+    }
+    eraseBufferLocked(minClientCacheId);
+
+    ClientCache::getInstance().unregisterErasedRecipient(minClientCacheId, this);
+}
+
+void BufferStateLayer::HwcSlotGenerator::eraseBufferLocked(const client_cache_t& clientCacheId)
+        REQUIRES(mMutex) {
+    auto itr = mCachedBuffers.find(clientCacheId);
+    if (itr == mCachedBuffers.end()) {
+        return;
+    }
+    auto& [hwcCacheSlot, counter] = itr->second;
+
+    // TODO send to hwc cache and resources
+
+    mFreeHwcCacheSlots.push(hwcCacheSlot);
+    mCachedBuffers.erase(clientCacheId);
+}
 } // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 864a15d..13186dd 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -25,8 +25,12 @@
 #include <system/window.h>
 #include <utils/String8.h>
 
+#include <stack>
+
 namespace android {
 
+class SlotGenerationTest;
+
 class BufferStateLayer : public BufferLayer {
 public:
     explicit BufferStateLayer(const LayerCreationArgs&);
@@ -63,8 +67,8 @@
     bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
     bool setCrop(const Rect& crop) override;
     bool setFrame(const Rect& frame) override;
-    bool setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime,
-                   nsecs_t desiredPresentTime) override;
+    bool setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime, nsecs_t desiredPresentTime,
+                   const client_cache_t& clientCacheId) override;
     bool setAcquireFence(const sp<Fence>& fence) override;
     bool setDataspace(ui::Dataspace dataspace) override;
     bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
@@ -132,6 +136,7 @@
     void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
 
 private:
+    friend class SlotGenerationTest;
     void onFirstRef() override;
     bool willPresentCurrentTransaction() const;
 
@@ -154,6 +159,46 @@
     nsecs_t mDesiredPresentTime = -1;
 
     // TODO(marissaw): support sticky transform for LEGACY camera mode
+
+    class HwcSlotGenerator : public ClientCache::ErasedRecipient {
+    public:
+        HwcSlotGenerator() {
+            for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+                mFreeHwcCacheSlots.push(i);
+            }
+        }
+
+        void bufferErased(const client_cache_t& clientCacheId);
+
+        uint32_t getHwcCacheSlot(const client_cache_t& clientCacheId);
+
+    private:
+        friend class SlotGenerationTest;
+        uint32_t addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex);
+        uint32_t getFreeHwcCacheSlot() REQUIRES(mMutex);
+        void evictLeastRecentlyUsed() REQUIRES(mMutex);
+        void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex);
+
+        struct CachedBufferHash {
+            std::size_t operator()(const client_cache_t& clientCacheId) const {
+                return std::hash<uint64_t>{}(clientCacheId.id);
+            }
+        };
+
+        std::mutex mMutex;
+
+        std::unordered_map<client_cache_t,
+                           std::pair<uint32_t /*HwcCacheSlot*/, uint32_t /*counter*/>,
+                           CachedBufferHash>
+                mCachedBuffers GUARDED_BY(mMutex);
+        std::stack<uint32_t /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex);
+
+        // The cache increments this counter value when a slot is updated or used.
+        // Used to track the least recently-used buffer
+        uint64_t mCounter = 0;
+    };
+
+    sp<HwcSlotGenerator> mHwcSlotGenerator;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
deleted file mode 100644
index 51ca45c..0000000
--- a/services/surfaceflinger/BufferStateLayerCache.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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 LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "BufferStateLayerCache"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include <cinttypes>
-
-#include "BufferStateLayerCache.h"
-
-namespace android {
-
-ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache);
-
-BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {}
-
-void BufferStateLayerCache::add(const sp<IBinder>& processToken, uint64_t id,
-                                const sp<GraphicBuffer>& buffer) {
-    if (!processToken) {
-        ALOGE("failed to cache buffer: invalid process token");
-        return;
-    }
-
-    if (!buffer) {
-        ALOGE("failed to cache buffer: invalid buffer");
-        return;
-    }
-
-    std::lock_guard lock(mMutex);
-
-    // If this is a new process token, set a death recipient. If the client process dies, we will
-    // get a callback through binderDied.
-    if (mBuffers.find(processToken) == mBuffers.end()) {
-        status_t err = processToken->linkToDeath(mDeathRecipient);
-        if (err != NO_ERROR) {
-            ALOGE("failed to cache buffer: could not link to death");
-            return;
-        }
-    }
-
-    auto& processBuffers = mBuffers[processToken];
-
-    if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
-        ALOGE("failed to cache buffer: cache is full");
-        return;
-    }
-
-    processBuffers[id] = buffer;
-}
-
-void BufferStateLayerCache::erase(const sp<IBinder>& processToken, uint64_t id) {
-    if (!processToken) {
-        ALOGE("failed to uncache buffer: invalid process token");
-        return;
-    }
-
-    std::lock_guard lock(mMutex);
-
-    if (mBuffers.find(processToken) == mBuffers.end()) {
-        ALOGE("failed to uncache buffer: process token not found");
-        return;
-    }
-
-    auto& processBuffers = mBuffers[processToken];
-    processBuffers.erase(id);
-}
-
-sp<GraphicBuffer> BufferStateLayerCache::get(const sp<IBinder>& processToken, uint64_t id) {
-    if (!processToken) {
-        ALOGE("failed to cache buffer: invalid process token");
-        return nullptr;
-    }
-
-    std::lock_guard lock(mMutex);
-    auto itr = mBuffers.find(processToken);
-    if (itr == mBuffers.end()) {
-        ALOGE("failed to get buffer: process token not found");
-        return nullptr;
-    }
-
-    if (itr->second.find(id) == itr->second.end()) {
-        ALOGE("failed to get buffer: buffer not found");
-        return nullptr;
-    }
-
-    return itr->second[id];
-}
-
-void BufferStateLayerCache::removeProcess(const wp<IBinder>& processToken) {
-    std::lock_guard lock(mMutex);
-    mBuffers.erase(processToken);
-}
-
-void BufferStateLayerCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) {
-    BufferStateLayerCache::getInstance().removeProcess(who);
-}
-
-}; // namespace android
diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h
deleted file mode 100644
index 415c09c..0000000
--- a/services/surfaceflinger/BufferStateLayerCache.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 <android-base/thread_annotations.h>
-#include <binder/IBinder.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/RefBase.h>
-#include <utils/Singleton.h>
-
-#include <array>
-#include <map>
-#include <mutex>
-
-#define BUFFER_CACHE_MAX_SIZE 64
-
-namespace android {
-
-class BufferStateLayerCache : public Singleton<BufferStateLayerCache> {
-public:
-    BufferStateLayerCache();
-
-    void add(const sp<IBinder>& processToken, uint64_t id, const sp<GraphicBuffer>& buffer);
-    void erase(const sp<IBinder>& processToken, uint64_t id);
-
-    sp<GraphicBuffer> get(const sp<IBinder>& processToken, uint64_t id);
-
-    void removeProcess(const wp<IBinder>& processToken);
-
-private:
-    std::mutex mMutex;
-    std::map<wp<IBinder> /*caching process*/, std::map<uint64_t /*Cache id*/, sp<GraphicBuffer>>>
-            mBuffers GUARDED_BY(mMutex);
-
-    class CacheDeathRecipient : public IBinder::DeathRecipient {
-    public:
-        void binderDied(const wp<IBinder>& who) override;
-    };
-
-    sp<CacheDeathRecipient> mDeathRecipient;
-};
-
-}; // namespace android
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
new file mode 100644
index 0000000..77f2f57
--- /dev/null
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -0,0 +1,202 @@
+/*
+ * 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 LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "ClientCache"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <cinttypes>
+
+#include "ClientCache.h"
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache);
+
+ClientCache::ClientCache() : mDeathRecipient(new CacheDeathRecipient) {}
+
+bool ClientCache::getBuffer(const client_cache_t& cacheId,
+                            ClientCacheBuffer** outClientCacheBuffer) {
+    auto& [processToken, id] = cacheId;
+    if (processToken == nullptr) {
+        ALOGE("failed to get buffer, invalid (nullptr) process token");
+        return false;
+    }
+    auto it = mBuffers.find(processToken);
+    if (it == mBuffers.end()) {
+        ALOGE("failed to get buffer, invalid process token");
+        return false;
+    }
+
+    auto& processBuffers = it->second;
+
+    auto bufItr = processBuffers.find(id);
+    if (bufItr == processBuffers.end()) {
+        ALOGE("failed to get buffer, invalid buffer id");
+        return false;
+    }
+
+    ClientCacheBuffer& buf = bufItr->second;
+    *outClientCacheBuffer = &buf;
+    return true;
+}
+
+void ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
+    auto& [processToken, id] = cacheId;
+    if (processToken == nullptr) {
+        ALOGE("failed to cache buffer: invalid process token");
+        return;
+    }
+
+    if (!buffer) {
+        ALOGE("failed to cache buffer: invalid buffer");
+        return;
+    }
+
+    std::lock_guard lock(mMutex);
+    sp<IBinder> token;
+
+    // If this is a new process token, set a death recipient. If the client process dies, we will
+    // get a callback through binderDied.
+    auto it = mBuffers.find(processToken);
+    if (it == mBuffers.end()) {
+        token = processToken.promote();
+        if (!token) {
+            ALOGE("failed to cache buffer: invalid token");
+            return;
+        }
+
+        status_t err = token->linkToDeath(mDeathRecipient);
+        if (err != NO_ERROR) {
+            ALOGE("failed to cache buffer: could not link to death");
+            return;
+        }
+        auto [itr, success] =
+                mBuffers.emplace(processToken, std::unordered_map<uint64_t, ClientCacheBuffer>());
+        LOG_ALWAYS_FATAL_IF(!success, "failed to insert new process into client cache");
+        it = itr;
+    }
+
+    auto& processBuffers = it->second;
+
+    if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
+        ALOGE("failed to cache buffer: cache is full");
+        return;
+    }
+
+    processBuffers[id].buffer = buffer;
+}
+
+void ClientCache::erase(const client_cache_t& cacheId) {
+    auto& [processToken, id] = cacheId;
+    std::vector<sp<ErasedRecipient>> pendingErase;
+    {
+        std::lock_guard lock(mMutex);
+        ClientCacheBuffer* buf = nullptr;
+        if (!getBuffer(cacheId, &buf)) {
+            ALOGE("failed to erase buffer, could not retrieve buffer");
+            return;
+        }
+
+        for (auto& recipient : buf->recipients) {
+            sp<ErasedRecipient> erasedRecipient = recipient.promote();
+            if (erasedRecipient) {
+                pendingErase.push_back(erasedRecipient);
+            }
+        }
+
+        mBuffers[processToken].erase(id);
+    }
+
+    for (auto& recipient : pendingErase) {
+        recipient->bufferErased(cacheId);
+    }
+}
+
+sp<GraphicBuffer> ClientCache::get(const client_cache_t& cacheId) {
+    std::lock_guard lock(mMutex);
+
+    ClientCacheBuffer* buf = nullptr;
+    if (!getBuffer(cacheId, &buf)) {
+        ALOGE("failed to get buffer, could not retrieve buffer");
+        return nullptr;
+    }
+
+    return buf->buffer;
+}
+
+void ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
+                                          const wp<ErasedRecipient>& recipient) {
+    std::lock_guard lock(mMutex);
+
+    ClientCacheBuffer* buf = nullptr;
+    if (!getBuffer(cacheId, &buf)) {
+        ALOGE("failed to register erased recipient, could not retrieve buffer");
+        return;
+    }
+    buf->recipients.insert(recipient);
+}
+
+void ClientCache::unregisterErasedRecipient(const client_cache_t& cacheId,
+                                            const wp<ErasedRecipient>& recipient) {
+    std::lock_guard lock(mMutex);
+
+    ClientCacheBuffer* buf = nullptr;
+    if (!getBuffer(cacheId, &buf)) {
+        ALOGE("failed to unregister erased recipient");
+        return;
+    }
+
+    buf->recipients.erase(recipient);
+}
+
+void ClientCache::removeProcess(const wp<IBinder>& processToken) {
+    std::vector<std::pair<sp<ErasedRecipient>, client_cache_t>> pendingErase;
+    {
+        if (processToken == nullptr) {
+            ALOGE("failed to remove process, invalid (nullptr) process token");
+            return;
+        }
+        std::lock_guard lock(mMutex);
+        auto itr = mBuffers.find(processToken);
+        if (itr == mBuffers.end()) {
+            ALOGE("failed to remove process, could not find process");
+            return;
+        }
+
+        for (auto& [id, clientCacheBuffer] : itr->second) {
+            client_cache_t cacheId = {processToken, id};
+            for (auto& recipient : clientCacheBuffer.recipients) {
+                sp<ErasedRecipient> erasedRecipient = recipient.promote();
+                if (erasedRecipient) {
+                    pendingErase.emplace_back(erasedRecipient, cacheId);
+                }
+            }
+        }
+        mBuffers.erase(itr);
+    }
+
+    for (auto& [recipient, cacheId] : pendingErase) {
+        recipient->bufferErased(cacheId);
+    }
+}
+
+void ClientCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) {
+    ClientCache::getInstance().removeProcess(who);
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h
new file mode 100644
index 0000000..9f057c4
--- /dev/null
+++ b/services/surfaceflinger/ClientCache.h
@@ -0,0 +1,78 @@
+/*
+ * 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 <android-base/thread_annotations.h>
+#include <binder/IBinder.h>
+#include <gui/LayerState.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/RefBase.h>
+#include <utils/Singleton.h>
+
+#include <map>
+#include <mutex>
+#include <set>
+#include <unordered_map>
+
+#define BUFFER_CACHE_MAX_SIZE 64
+
+namespace android {
+
+class ClientCache : public Singleton<ClientCache> {
+public:
+    ClientCache();
+
+    void add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer);
+    void erase(const client_cache_t& cacheId);
+
+    sp<GraphicBuffer> get(const client_cache_t& cacheId);
+
+    void removeProcess(const wp<IBinder>& processToken);
+
+    class ErasedRecipient : public virtual RefBase {
+    public:
+        virtual void bufferErased(const client_cache_t& clientCacheId) = 0;
+    };
+
+    void registerErasedRecipient(const client_cache_t& cacheId,
+                                 const wp<ErasedRecipient>& recipient);
+    void unregisterErasedRecipient(const client_cache_t& cacheId,
+                                   const wp<ErasedRecipient>& recipient);
+
+private:
+    std::mutex mMutex;
+
+    struct ClientCacheBuffer {
+        sp<GraphicBuffer> buffer;
+        std::set<wp<ErasedRecipient>> recipients;
+    };
+    std::map<wp<IBinder> /*caching process*/,
+             std::unordered_map<uint64_t /*cache id*/, ClientCacheBuffer>>
+            mBuffers GUARDED_BY(mMutex);
+
+    class CacheDeathRecipient : public IBinder::DeathRecipient {
+    public:
+        void binderDied(const wp<IBinder>& who) override;
+    };
+
+    sp<CacheDeathRecipient> mDeathRecipient;
+
+    bool getBuffer(const client_cache_t& cacheId, ClientCacheBuffer** outClientCacheBuffer)
+            REQUIRES(mMutex);
+};
+
+}; // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index 97bdc8f..8eec035 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -48,20 +48,11 @@
     void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                       sp<GraphicBuffer>* outBuffer);
 
-protected:
-    bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot);
-    uint32_t getLeastRecentlyUsedSlot();
-    uint64_t getCounter();
-
 private:
     // an array where the index corresponds to a slot and the value corresponds to a (counter,
     // buffer) pair. "counter" is a unique value that indicates the last time this slot was updated
     // or used and allows us to keep track of the least-recently used buffer.
-    std::pair<uint64_t, wp<GraphicBuffer>> mBuffers[BufferQueue::NUM_BUFFER_SLOTS];
-
-    // The cache increments this counter value when a slot is updated or used.
-    // Used to track the least recently-used buffer
-    uint64_t mCounter = 1;
+    wp<GraphicBuffer> mBuffers[BufferQueue::NUM_BUFFER_SLOTS];
 };
 
 } // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index a941e09..f72862b 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -21,60 +21,30 @@
 namespace android::compositionengine::impl {
 
 HwcBufferCache::HwcBufferCache() {
-    std::fill(std::begin(mBuffers), std::end(mBuffers),
-              std::pair<uint64_t, wp<GraphicBuffer>>(0, nullptr));
-}
-bool HwcBufferCache::getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
-    // search for cached buffer first
-    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
-        // Weak pointers in the cache may have had their object destroyed.
-        // Comparisons between weak pointers will accurately reflect this case,
-        // but comparisons between weak and strong may not.  Thus, we create a weak
-        // pointer from strong pointer buffer
-        wp<GraphicBuffer> weakCopy(buffer);
-        if (mBuffers[i].second == weakCopy) {
-            *outSlot = i;
-            return true;
-        }
-    }
-
-    // use the least-recently used slot
-    *outSlot = getLeastRecentlyUsedSlot();
-    return false;
-}
-
-uint32_t HwcBufferCache::getLeastRecentlyUsedSlot() {
-    auto iter = std::min_element(std::begin(mBuffers), std::end(mBuffers));
-    return std::distance(std::begin(mBuffers), iter);
+    std::fill(std::begin(mBuffers), std::end(mBuffers), wp<GraphicBuffer>(nullptr));
 }
 
 void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                                   sp<GraphicBuffer>* outBuffer) {
-    // if this slot corresponds to a BufferStateLayer, generate the slot
-    if (slot == BufferQueue::INVALID_BUFFER_SLOT) {
-        getSlot(buffer, outSlot);
-    } else if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
+    // default is 0
+    if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0 ||
+        slot >= BufferQueue::NUM_BUFFER_SLOTS) {
         *outSlot = 0;
     } else {
         *outSlot = slot;
     }
 
-    auto& [currentCounter, currentBuffer] = mBuffers[*outSlot];
+    auto& currentBuffer = mBuffers[*outSlot];
     wp<GraphicBuffer> weakCopy(buffer);
     if (currentBuffer == weakCopy) {
         // already cached in HWC, skip sending the buffer
         *outBuffer = nullptr;
-        currentCounter = getCounter();
     } else {
         *outBuffer = buffer;
 
         // update cache
         currentBuffer = buffer;
-        currentCounter = getCounter();
     }
 }
 
-uint64_t HwcBufferCache::getCounter() {
-    return mCounter++;
-}
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
index b261493..00eafb1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -28,10 +28,6 @@
                       sp<GraphicBuffer>* outBuffer) {
         HwcBufferCache::getHwcBuffer(slot, buffer, outSlot, outBuffer);
     }
-    bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
-        return HwcBufferCache::getSlot(buffer, outSlot);
-    }
-    uint32_t getLeastRecentlyUsedSlot() { return HwcBufferCache::getLeastRecentlyUsedSlot(); }
 };
 
 class HwcBufferCacheTest : public testing::Test {
@@ -86,41 +82,5 @@
     testSlot(-123, 0);
 }
 
-TEST_F(HwcBufferCacheTest, cacheGeneratesSlotForInvalidBufferSlot) {
-    uint32_t outSlot;
-    sp<GraphicBuffer> outBuffer;
-
-    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer);
-    EXPECT_EQ(0, outSlot);
-    EXPECT_EQ(mBuffer1, outBuffer);
-
-    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer);
-    EXPECT_EQ(0, outSlot);
-    EXPECT_EQ(nullptr, outBuffer.get());
-
-    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
-    EXPECT_EQ(1, outSlot);
-    EXPECT_EQ(mBuffer2, outBuffer);
-
-    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
-    EXPECT_EQ(1, outSlot);
-    EXPECT_EQ(nullptr, outBuffer.get());
-
-    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, sp<GraphicBuffer>(), &outSlot,
-                        &outBuffer);
-    EXPECT_EQ(2, outSlot);
-    EXPECT_EQ(nullptr, outBuffer.get());
-
-    // note that sending mBuffer1 with explicit slot 1 will overwrite mBuffer2
-    // and also cause mBuffer1 to be stored in two places
-    mCache.getHwcBuffer(1, mBuffer1, &outSlot, &outBuffer);
-    EXPECT_EQ(1, outSlot);
-    EXPECT_EQ(mBuffer1, outBuffer);
-
-    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
-    EXPECT_EQ(3, outSlot);
-    EXPECT_EQ(mBuffer2, outBuffer);
-}
-
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 9690605..3012ed8 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -1029,9 +1029,13 @@
     if (matrix == mColorMatrix) {
         return Error::None;
     }
-    mColorMatrix = matrix;
     auto intError = mComposer.setLayerColorTransform(mDisplayId, mId, matrix.asArray());
-    return static_cast<Error>(intError);
+    Error error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+    mColorMatrix = matrix;
+    return error;
 }
 
 } // namespace impl
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f4545e0..c76394c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -199,6 +199,7 @@
         Region transparentRegionHint;
 
         sp<GraphicBuffer> buffer;
+        client_cache_t clientCacheId;
         sp<Fence> acquireFence;
         HdrMetadata hdrMetadata;
         Region surfaceDamageRegion;
@@ -312,9 +313,10 @@
     virtual bool setCrop(const Rect& /*crop*/) { return false; };
     virtual bool setFrame(const Rect& /*frame*/) { return false; };
     virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, nsecs_t /*postTime*/,
-                           nsecs_t /*desiredPresentTime*/) {
+                           nsecs_t /*desiredPresentTime*/,
+                           const client_cache_t& /*clientCacheId*/) {
         return false;
-    }
+    };
     virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
     virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
     virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ad58717..3744f8b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -75,7 +75,6 @@
 #include "BufferLayer.h"
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
-#include "BufferStateLayerCache.h"
 #include "Client.h"
 #include "ColorLayer.h"
 #include "Colorizer.h"
@@ -2884,7 +2883,7 @@
 }
 
 void SurfaceFlinger::commitInputWindowCommands() {
-    mInputWindowCommands.merge(mPendingInputWindowCommands);
+    mInputWindowCommands = mPendingInputWindowCommands;
     mPendingInputWindowCommands.clear();
 }
 
@@ -3545,7 +3544,7 @@
                                          const sp<IBinder>& applyToken,
                                          const InputWindowCommands& inputWindowCommands,
                                          int64_t desiredPresentTime,
-                                         const cached_buffer_t& uncacheBuffer,
+                                         const client_cache_t& uncacheBuffer,
                                          const std::vector<ListenerCallbacks>& listenerCallbacks) {
     ATRACE_CALL();
 
@@ -3577,7 +3576,7 @@
                                            const Vector<DisplayState>& displays, uint32_t flags,
                                            const InputWindowCommands& inputWindowCommands,
                                            const int64_t desiredPresentTime,
-                                           const cached_buffer_t& uncacheBuffer,
+                                           const client_cache_t& uncacheBuffer,
                                            const std::vector<ListenerCallbacks>& listenerCallbacks,
                                            const int64_t postTime, bool privileged,
                                            bool isMainThread) {
@@ -3586,7 +3585,7 @@
     if (flags & eAnimation) {
         // For window updates that are part of an animation we must wait for
         // previous animation "frames" to be handled.
-        while (mAnimTransactionPending) {
+        while (!isMainThread && mAnimTransactionPending) {
             status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
             if (CC_UNLIKELY(err != NO_ERROR)) {
                 // just in case something goes wrong in SF, return to the
@@ -3627,8 +3626,8 @@
 
     transactionFlags |= addInputWindowCommands(inputWindowCommands);
 
-    if (uncacheBuffer.token) {
-        BufferStateLayerCache::getInstance().erase(uncacheBuffer.token, uncacheBuffer.cacheId);
+    if (uncacheBuffer.isValid()) {
+        ClientCache::getInstance().erase(uncacheBuffer);
     }
 
     // If a synchronous transaction is explicitly requested without any changes, force a transaction
@@ -3665,8 +3664,9 @@
         if (flags & eAnimation) {
             mAnimTransactionPending = true;
         }
-
-        mPendingSyncInputWindows = mPendingInputWindowCommands.syncInputWindows;
+        if (mPendingInputWindowCommands.syncInputWindows) {
+            mPendingSyncInputWindows = true;
+        }
 
         // applyTransactionState can be called by either the main SF thread or by
         // another process through setTransactionState.  While a given process may wish
@@ -3983,17 +3983,15 @@
     bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
     sp<GraphicBuffer> buffer;
     if (bufferChanged && cacheIdChanged) {
-        BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.cacheId,
-                                                 s.buffer);
+        ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
         buffer = s.buffer;
     } else if (cacheIdChanged) {
-        buffer = BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
-                                                          s.cachedBuffer.cacheId);
+        buffer = ClientCache::getInstance().get(s.cachedBuffer);
     } else if (bufferChanged) {
         buffer = s.buffer;
     }
     if (buffer) {
-        if (layer->setBuffer(buffer, postTime, desiredPresentTime)) {
+        if (layer->setBuffer(buffer, postTime, desiredPresentTime, s.cachedBuffer)) {
             flags |= eTraversalNeeded;
         }
     }
@@ -5875,12 +5873,15 @@
 
     Mutex::Autolock lock(mStateLock);
 
-    if (displayToken != getInternalDisplayTokenLocked()) {
-        ALOGE("%s is only supported for the internal display", __FUNCTION__);
+    const auto display = getDisplayDeviceLocked(displayToken);
+    if (!display) {
         return NAME_NOT_FOUND;
     }
 
-    outAllowedConfigs->assign(mAllowedDisplayConfigs.begin(), mAllowedDisplayConfigs.end());
+    if (display->isPrimary()) {
+        outAllowedConfigs->assign(mAllowedDisplayConfigs.begin(), mAllowedDisplayConfigs.end());
+    }
+
     return NO_ERROR;
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 825b7aa..13b2182 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -46,6 +46,7 @@
 #include <utils/Trace.h>
 #include <utils/threads.h>
 
+#include "ClientCache.h"
 #include "DisplayDevice.h"
 #include "DisplayHardware/HWC2.h"
 #include "DisplayHardware/PowerAdvisor.h"
@@ -386,7 +387,7 @@
                              const Vector<DisplayState>& displays, uint32_t flags,
                              const sp<IBinder>& applyToken,
                              const InputWindowCommands& inputWindowCommands,
-                             int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer,
+                             int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
                              const std::vector<ListenerCallbacks>& listenerCallbacks) override;
     void bootFinished() override;
     bool authenticateSurfaceTexture(
@@ -545,7 +546,7 @@
                                const Vector<DisplayState>& displays, uint32_t flags,
                                const InputWindowCommands& inputWindowCommands,
                                const int64_t desiredPresentTime,
-                               const cached_buffer_t& uncacheBuffer,
+                               const client_cache_t& uncacheBuffer,
                                const std::vector<ListenerCallbacks>& listenerCallbacks,
                                const int64_t postTime, bool privileged, bool isMainThread = false)
             REQUIRES(mStateLock);
@@ -1031,7 +1032,7 @@
     struct TransactionState {
         TransactionState(const Vector<ComposerState>& composerStates,
                          const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
-                         int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer,
+                         int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
                          const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
                          bool privileged)
               : states(composerStates),
@@ -1047,7 +1048,7 @@
         Vector<DisplayState> displays;
         uint32_t flags;
         const int64_t desiredPresentTime;
-        cached_buffer_t buffer;
+        client_cache_t buffer;
         std::vector<ListenerCallbacks> callback;
         const int64_t postTime;
         bool privileged;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 85e9ce5..f842d61 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -35,7 +35,8 @@
     srcs: [
         ":libsurfaceflinger_sources",
         "libsurfaceflinger_unittest_main.cpp",
-        "CompositionTest.cpp",
+        "CachingTest.cpp",
+	"CompositionTest.cpp",
         "DispSyncSourceTest.cpp",
         "DisplayIdentificationTest.cpp",
         "DisplayTransactionTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp
new file mode 100644
index 0000000..74ce540
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "CachingTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/BufferQueue.h>
+#include "BufferStateLayer.h"
+
+namespace android {
+
+class SlotGenerationTest : public testing::Test {
+protected:
+    BufferStateLayer::HwcSlotGenerator mHwcSlotGenerator;
+    sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+    sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+    sp<GraphicBuffer> mBuffer3{new GraphicBuffer(10, 10, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+};
+
+TEST_F(SlotGenerationTest, getHwcCacheSlot_Invalid) {
+    sp<IBinder> binder = new BBinder();
+    // test getting invalid client_cache_id
+    client_cache_t id;
+    uint32_t slot = mHwcSlotGenerator.getHwcCacheSlot(id);
+    EXPECT_EQ(BufferQueue::INVALID_BUFFER_SLOT, slot);
+}
+
+TEST_F(SlotGenerationTest, getHwcCacheSlot_Basic) {
+    sp<IBinder> binder = new BBinder();
+    client_cache_t id;
+    id.token = binder;
+    id.id = 0;
+    uint32_t slot = mHwcSlotGenerator.getHwcCacheSlot(id);
+    EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - 1, slot);
+
+    client_cache_t idB;
+    idB.token = binder;
+    idB.id = 1;
+    slot = mHwcSlotGenerator.getHwcCacheSlot(idB);
+    EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - 2, slot);
+
+    slot = mHwcSlotGenerator.getHwcCacheSlot(idB);
+    EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - 2, slot);
+
+    slot = mHwcSlotGenerator.getHwcCacheSlot(id);
+    EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - 1, slot);
+}
+
+TEST_F(SlotGenerationTest, getHwcCacheSlot_Reuse) {
+    sp<IBinder> binder = new BBinder();
+    std::vector<client_cache_t> ids;
+    uint32_t cacheId = 0;
+    // fill up cache
+    for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        client_cache_t id;
+        id.token = binder;
+        id.id = cacheId;
+        ids.push_back(id);
+
+        uint32_t slot = mHwcSlotGenerator.getHwcCacheSlot(id);
+        EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot);
+        cacheId++;
+    }
+    for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        uint32_t slot = mHwcSlotGenerator.getHwcCacheSlot(ids[i]);
+        EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot);
+    }
+
+    for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        client_cache_t id;
+        id.token = binder;
+        id.id = cacheId;
+        uint32_t slot = mHwcSlotGenerator.getHwcCacheSlot(id);
+        EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot);
+        cacheId++;
+    }
+}
+} // namespace android