Merge "blast: implicitly cache buffers"
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index bef68ef..fd30e3b 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -722,42 +722,6 @@
         return error;
     }
 
-    virtual status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
-                                 int32_t* outBufferId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-
-        data.writeStrongBinder(token);
-        if (buffer) {
-            data.writeBool(true);
-            data.write(*buffer);
-        } else {
-            data.writeBool(false);
-        }
-
-        status_t result = remote()->transact(BnSurfaceComposer::CACHE_BUFFER, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-
-        int32_t id = -1;
-        result = reply.readInt32(&id);
-        if (result == NO_ERROR) {
-            *outBufferId = id;
-        }
-        return result;
-    }
-
-    virtual status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-
-        data.writeStrongBinder(token);
-        data.writeInt32(bufferId);
-
-        return remote()->transact(BnSurfaceComposer::UNCACHE_BUFFER, data, &reply);
-    }
-
     virtual status_t isWideColorDisplay(const sp<IBinder>& token,
                                         bool* outIsWideColorDisplay) const {
         Parcel data, reply;
@@ -1238,48 +1202,6 @@
             }
             return error;
         }
-        case CACHE_BUFFER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> token;
-            status_t result = data.readStrongBinder(&token);
-            if (result != NO_ERROR) {
-                ALOGE("cache buffer failure in reading token: %d", result);
-                return result;
-            }
-
-            sp<GraphicBuffer> buffer = new GraphicBuffer();
-            if (data.readBool()) {
-                result = data.read(*buffer);
-                if (result != NO_ERROR) {
-                    ALOGE("cache buffer failure in reading buffer: %d", result);
-                    return result;
-                }
-            }
-            int32_t bufferId = -1;
-            status_t error = cacheBuffer(token, buffer, &bufferId);
-            if (error == NO_ERROR) {
-                reply->writeInt32(bufferId);
-            }
-            return error;
-        }
-        case UNCACHE_BUFFER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> token;
-            status_t result = data.readStrongBinder(&token);
-            if (result != NO_ERROR) {
-                ALOGE("uncache buffer failure in reading token: %d", result);
-                return result;
-            }
-
-            int32_t bufferId = -1;
-            result = data.readInt32(&bufferId);
-            if (result != NO_ERROR) {
-                ALOGE("uncache buffer failure in reading buffer id: %d", result);
-                return result;
-            }
-
-            return uncacheBuffer(token, bufferId);
-        }
         case IS_WIDE_COLOR_DISPLAY: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = nullptr;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 51385b8..92b5588 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -48,6 +48,9 @@
 
 #include <private/gui/ComposerService.h>
 
+// This server size should always be smaller than the server cache size
+#define BUFFER_CACHE_MAX_SIZE 64
+
 namespace android {
 
 using ui::ColorMode;
@@ -230,6 +233,113 @@
 
 // ---------------------------------------------------------------------------
 
+class BufferCache : public Singleton<BufferCache> {
+public:
+    BufferCache() : token(new BBinder()) {}
+
+    sp<IBinder> getToken() {
+        return IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    }
+
+    int32_t getId(const sp<GraphicBuffer>& buffer) {
+        std::lock_guard lock(mMutex);
+
+        auto itr = mBuffers.find(buffer);
+        if (itr == mBuffers.end()) {
+            return -1;
+        }
+        itr->second.counter = getCounter();
+        return itr->second.id;
+    }
+
+    int32_t cache(const sp<GraphicBuffer>& buffer) {
+        std::lock_guard lock(mMutex);
+
+        int32_t bufferId = getNextAvailableId();
+
+        mBuffers[buffer].id = bufferId;
+        mBuffers[buffer].counter = getCounter();
+        return bufferId;
+    }
+
+private:
+    int32_t evictDestroyedBuffer() REQUIRES(mMutex) {
+        auto itr = mBuffers.begin();
+        while (itr != mBuffers.end()) {
+            auto& buffer = itr->first;
+            if (buffer == nullptr || buffer.promote() == nullptr) {
+                int32_t bufferId = itr->second.id;
+                mBuffers.erase(itr);
+                return bufferId;
+            }
+            itr++;
+        }
+        return -1;
+    }
+
+    int32_t evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) {
+        if (mBuffers.size() < 0) {
+            return -1;
+        }
+        auto itr = mBuffers.begin();
+        uint64_t minCounter = itr->second.counter;
+        auto minBuffer = itr;
+        itr++;
+
+        while (itr != mBuffers.end()) {
+            uint64_t counter = itr->second.counter;
+            if (counter < minCounter) {
+                minCounter = counter;
+                minBuffer = itr;
+            }
+            itr++;
+        }
+        int32_t minBufferId = minBuffer->second.id;
+        mBuffers.erase(minBuffer);
+        return minBufferId;
+    }
+
+    int32_t getNextAvailableId() REQUIRES(mMutex) {
+        static int32_t id = 0;
+        if (id + 1 < BUFFER_CACHE_MAX_SIZE) {
+            return id++;
+        }
+
+        // There are no more valid cache ids. To set additional buffers, evict existing buffers
+        // and reuse their cache ids.
+        int32_t bufferId = evictDestroyedBuffer();
+        if (bufferId > 0) {
+            return bufferId;
+        }
+        return evictLeastRecentlyUsedBuffer();
+    }
+
+    uint64_t getCounter() REQUIRES(mMutex) {
+        static uint64_t counter = 0;
+        return counter++;
+    }
+
+    struct Metadata {
+        // The cache id of a buffer that can be set to ISurfaceComposer. When ISurfaceComposer
+        // recieves this id, it can retrieve the buffer from its cache. Caching GraphicBuffers
+        // is important because sending them across processes is expensive.
+        int32_t id = 0;
+        // When a buffer is set, a counter is incremented and stored in the cache's metadata.
+        // When an buffer must be evicted, the entry with the lowest counter value is chosen.
+        uint64_t counter = 0;
+    };
+
+    std::mutex mMutex;
+    std::map<wp<GraphicBuffer>, Metadata> mBuffers GUARDED_BY(mMutex);
+
+    // Used by ISurfaceComposer to identify which process is sending the cached buffer.
+    sp<IBinder> token;
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache);
+
+// ---------------------------------------------------------------------------
+
 SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
       : mForceSynchronous(other.mForceSynchronous),
         mTransactionNestCount(other.mTransactionNestCount),
@@ -759,22 +869,17 @@
         mStatus = BAD_INDEX;
         return *this;
     }
-    s->what |= layer_state_t::eBufferChanged;
-    s->buffer = buffer;
 
-    registerSurfaceControlForCallback(sc);
-    return *this;
-}
+    int32_t bufferId = BufferCache::getInstance().getId(buffer);
+    if (bufferId < 0) {
+        bufferId = BufferCache::getInstance().cache(buffer);
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachedBuffer(
-        const sp<SurfaceControl>& sc, int32_t bufferId) {
-    layer_state_t* s = getLayerState(sc);
-    if (!s) {
-        mStatus = BAD_INDEX;
-        return *this;
+        s->what |= layer_state_t::eBufferChanged;
+        s->buffer = buffer;
     }
+
     s->what |= layer_state_t::eCachedBufferChanged;
-    s->cachedBuffer.token = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    s->cachedBuffer.token = BufferCache::getInstance().getToken();
     s->cachedBuffer.bufferId = bufferId;
 
     registerSurfaceControlForCallback(sc);
@@ -1217,26 +1322,6 @@
 
 // ----------------------------------------------------------------------------
 
-status_t SurfaceComposerClient::cacheBuffer(const sp<GraphicBuffer>& buffer, int32_t* outBufferId) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    if (buffer == nullptr || outBufferId == nullptr) {
-        return BAD_VALUE;
-    }
-    return sf->cacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()),
-                           buffer, outBufferId);
-}
-
-status_t SurfaceComposerClient::uncacheBuffer(int32_t bufferId) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    if (bufferId < 0) {
-        return BAD_VALUE;
-    }
-    return sf->uncacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()),
-                             bufferId);
-}
-
-// ----------------------------------------------------------------------------
-
 status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     return sf->enableVSyncInjections(enable);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 3899f6a..7146b7d 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -320,11 +320,6 @@
      */
     virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
 
-    virtual status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
-                                 int32_t* outBufferId) = 0;
-
-    virtual status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) = 0;
-
     /*
      * Queries whether the given display is a wide color display.
      * Requires the ACCESS_SURFACE_FLINGER permission.
@@ -373,8 +368,6 @@
         SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
         GET_DISPLAYED_CONTENT_SAMPLE,
         GET_PROTECTED_CONTENT_SUPPORT,
-        CACHE_BUFFER,
-        UNCACHE_BUFFER,
         IS_WIDE_COLOR_DISPLAY,
         GET_DISPLAY_NATIVE_PRIMARIES,
         // Always append new enum to the end.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index a95664b..044106d 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -152,12 +152,6 @@
     static void doDropReferenceTransaction(const sp<IBinder>& handle,
             const sp<ISurfaceComposerClient>& client);
 
-    // Caches a buffer with the ISurfaceComposer so the buffer does not need to be resent across
-    // processes
-    static status_t cacheBuffer(const sp<GraphicBuffer>& buffer, int32_t* outBufferId);
-    // Uncaches a buffer set by cacheBuffer
-    static status_t uncacheBuffer(int32_t bufferId);
-
     // Queries whether a given display is wide color display.
     static status_t isWideColorDisplay(const sp<IBinder>& display, bool* outIsWideColorDisplay);
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 1705fd7..8bd589d 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -664,11 +664,6 @@
     status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
     status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
 
-    status_t cacheBuffer(const sp<IBinder>& /*token*/, const sp<GraphicBuffer>& /*buffer*/,
-                         int32_t* /*outBufferId*/) {
-        return NO_ERROR;
-    }
-    status_t uncacheBuffer(const sp<IBinder>& /*token*/, int32_t /*bufferId*/) { return NO_ERROR; }
     status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
 
 protected:
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
index c82ad7b..cb02d16 100644
--- a/services/surfaceflinger/BufferStateLayerCache.cpp
+++ b/services/surfaceflinger/BufferStateLayerCache.cpp
@@ -19,81 +19,84 @@
 #define LOG_TAG "BufferStateLayerCache"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
+#include <cinttypes>
+
 #include "BufferStateLayerCache.h"
 
-#define MAX_CACHE_SIZE 64
+#define VALID_CACHE_ID(id) ((id) >= 0 || (id) < (BUFFER_CACHE_MAX_SIZE))
 
 namespace android {
 
-int32_t BufferStateLayerCache::add(const sp<IBinder>& processToken,
-                                   const sp<GraphicBuffer>& buffer) {
-    std::lock_guard lock(mMutex);
+ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache);
 
-    auto& processCache = getProccessCache(processToken);
+BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {}
 
-    int32_t slot = findSlot(processCache);
-    if (slot < 0) {
-        return slot;
+void BufferStateLayerCache::add(sp<IBinder> processToken, int32_t id,
+                                const sp<GraphicBuffer>& buffer) {
+    if (!VALID_CACHE_ID(id)) {
+        ALOGE("failed to cache buffer: invalid buffer id");
+        return;
     }
 
-    processCache[slot] = buffer;
+    if (!processToken) {
+        ALOGE("failed to cache buffer: invalid process token");
+        return;
+    }
 
-    return slot;
-}
-
-void BufferStateLayerCache::release(const sp<IBinder>& processToken, int32_t id) {
-    if (id < 0) {
-        ALOGE("invalid buffer id");
+    if (!buffer) {
+        ALOGE("failed to cache buffer: invalid buffer");
         return;
     }
 
     std::lock_guard lock(mMutex);
-    auto& processCache = getProccessCache(processToken);
 
-    if (id >= processCache.size()) {
-        ALOGE("invalid buffer id");
-        return;
-    }
-    processCache[id] = nullptr;
-}
-
-sp<GraphicBuffer> BufferStateLayerCache::get(const sp<IBinder>& processToken, int32_t id) {
-    if (id < 0) {
-        ALOGE("invalid buffer id");
-        return nullptr;
-    }
-
-    std::lock_guard lock(mMutex);
-    auto& processCache = getProccessCache(processToken);
-
-    if (id >= processCache.size()) {
-        ALOGE("invalid buffer id");
-        return nullptr;
-    }
-    return processCache[id];
-}
-
-std::vector<sp<GraphicBuffer>>& BufferStateLayerCache::getProccessCache(
-        const sp<IBinder>& processToken) {
-    return mBuffers[processToken];
-}
-
-int32_t BufferStateLayerCache::findSlot(std::vector<sp<GraphicBuffer>>& processCache) {
-    int32_t slot = 0;
-
-    for (const sp<GraphicBuffer> buffer : processCache) {
-        if (!buffer) {
-            return slot;
+    // 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;
         }
-        slot++;
     }
 
-    if (processCache.size() < MAX_CACHE_SIZE) {
-        processCache.push_back(nullptr);
-        return slot;
+    auto& processBuffers = mBuffers[processToken];
+    processBuffers[id] = buffer;
+}
+
+sp<GraphicBuffer> BufferStateLayerCache::get(sp<IBinder> processToken, int32_t id) {
+    if (!VALID_CACHE_ID(id)) {
+        ALOGE("failed to get buffer: invalid buffer id");
+        return nullptr;
     }
 
-    return -1;
+    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 (id >= itr->second.size()) {
+        ALOGE("failed to get buffer: id outside the bounds of the cache");
+        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
index 623f0c6..ede3feb 100644
--- a/services/surfaceflinger/BufferStateLayerCache.h
+++ b/services/surfaceflinger/BufferStateLayerCache.h
@@ -20,36 +20,36 @@
 #include <binder/IBinder.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/RefBase.h>
+#include <utils/Singleton.h>
 
+#include <array>
+#include <map>
 #include <mutex>
-#include <unordered_map>
-#include <vector>
+
+#define BUFFER_CACHE_MAX_SIZE 64
 
 namespace android {
 
-class BufferStateLayerCache {
+class BufferStateLayerCache : public Singleton<BufferStateLayerCache> {
 public:
-    int32_t add(const sp<IBinder>& processToken, const sp<GraphicBuffer>& buffer);
-    void release(const sp<IBinder>& processToken, int32_t id);
+    BufferStateLayerCache();
 
-    sp<GraphicBuffer> get(const sp<IBinder>& processToken, int32_t id);
+    void add(sp<IBinder> processToken, int32_t id, const sp<GraphicBuffer>& buffer);
+    sp<GraphicBuffer> get(sp<IBinder> processToken, int32_t id);
+
+    void removeProcess(const wp<IBinder>& processToken);
 
 private:
     std::mutex mMutex;
+    std::map<wp<IBinder> /*caching process*/, std::array<sp<GraphicBuffer>, BUFFER_CACHE_MAX_SIZE>>
+            mBuffers GUARDED_BY(mMutex);
 
-    std::vector<sp<GraphicBuffer>>& getProccessCache(const sp<IBinder>& processToken)
-            REQUIRES(mMutex);
-
-    int32_t findSlot(std::vector<sp<GraphicBuffer>>& proccessCache) REQUIRES(mMutex);
-
-    struct IBinderHash {
-        std::size_t operator()(const sp<IBinder>& strongPointer) const {
-            return std::hash<IBinder*>{}(strongPointer.get());
-        }
+    class CacheDeathRecipient : public IBinder::DeathRecipient {
+    public:
+        void binderDied(const wp<IBinder>& who) override;
     };
 
-    std::unordered_map<sp<IBinder> /*caching process*/, std::vector<sp<GraphicBuffer>>, IBinderHash>
-            mBuffers GUARDED_BY(mMutex);
+    sp<CacheDeathRecipient> mDeathRecipient;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index baefb15..9d03ae7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1159,20 +1159,6 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
-                                     int32_t* outBufferId) {
-    if (!outBufferId) {
-        return BAD_VALUE;
-    }
-    *outBufferId = mBufferStateLayerCache.add(token, buffer);
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
-    mBufferStateLayerCache.release(token, bufferId);
-    return NO_ERROR;
-}
-
 status_t SurfaceFlinger::isWideColorDisplay(const sp<IBinder>& displayToken,
                                             bool* outIsWideColorDisplay) const {
     if (!displayToken || !outIsWideColorDisplay) {
@@ -3999,9 +3985,6 @@
     if (what & layer_state_t::eFrameChanged) {
         if (layer->setFrame(s.frame)) flags |= eTraversalNeeded;
     }
-    if (what & layer_state_t::eBufferChanged) {
-        if (layer->setBuffer(s.buffer)) flags |= eTraversalNeeded;
-    }
     if (what & layer_state_t::eAcquireFenceChanged) {
         if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded;
     }
@@ -4038,9 +4021,16 @@
             callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
         }
     }
+
+    if (what & layer_state_t::eBufferChanged) {
+        // Add the new buffer to the cache. This should always come before eCachedBufferChanged.
+        BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.bufferId,
+                                                 s.buffer);
+    }
     if (what & layer_state_t::eCachedBufferChanged) {
         sp<GraphicBuffer> buffer =
-                mBufferStateLayerCache.get(s.cachedBuffer.token, s.cachedBuffer.bufferId);
+                BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
+                                                         s.cachedBuffer.bufferId);
         if (layer->setBuffer(buffer)) flags |= eTraversalNeeded;
     }
     if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
@@ -5022,8 +5012,6 @@
         case GET_COLOR_MANAGEMENT:
         case GET_COMPOSITION_PREFERENCE:
         case GET_PROTECTED_CONTENT_SUPPORT:
-        case CACHE_BUFFER:
-        case UNCACHE_BUFFER:
         case IS_WIDE_COLOR_DISPLAY: {
             return OK;
         }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 689ec1c..a127550 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -467,9 +467,6 @@
                                        uint64_t timestamp,
                                        DisplayedFrameStats* outStats) const override;
     status_t getProtectedContentSupport(bool* outSupported) const override;
-    status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
-                         int32_t* outBufferId) override;
-    status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) override;
     status_t isWideColorDisplay(const sp<IBinder>& displayToken,
                                 bool* outIsWideColorDisplay) const override;
 
@@ -1089,8 +1086,6 @@
 
     InputWindowCommands mInputWindowCommands;
 
-    BufferStateLayerCache mBufferStateLayerCache;
-
     ui::DisplayPrimaries mInternalDisplayPrimaries;
 };
 }; // namespace android
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4f0ded3..e631295 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2405,6 +2405,117 @@
     }
 }
 
+TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+    std::array<sp<GraphicBuffer>, 10> buffers;
+
+    size_t idx = 0;
+    for (auto& buffer : buffers) {
+        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                                   BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                           BufferUsage::COMPOSER_OVERLAY,
+                                   "test");
+        Color color = colors[idx % colors.size()];
+        fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+        idx++;
+    }
+
+    // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+    // cache is working.
+    idx = 0;
+    for (auto& buffer : buffers) {
+        for (int i = 0; i < 2; i++) {
+            Transaction().setBuffer(layer, buffer).apply();
+
+            Color color = colors[idx % colors.size()];
+            auto shot = screenshot();
+            shot->expectColor(Rect(0, 0, 32, 32), color);
+            shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+        }
+        idx++;
+    }
+}
+
+TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+    std::array<sp<GraphicBuffer>, 70> buffers;
+
+    size_t idx = 0;
+    for (auto& buffer : buffers) {
+        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                                   BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                           BufferUsage::COMPOSER_OVERLAY,
+                                   "test");
+        Color color = colors[idx % colors.size()];
+        fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+        idx++;
+    }
+
+    // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+    // cache is working.
+    idx = 0;
+    for (auto& buffer : buffers) {
+        for (int i = 0; i < 2; i++) {
+            Transaction().setBuffer(layer, buffer).apply();
+
+            Color color = colors[idx % colors.size()];
+            auto shot = screenshot();
+            shot->expectColor(Rect(0, 0, 32, 32), color);
+            shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+        }
+        idx++;
+    }
+}
+
+TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+    std::array<sp<GraphicBuffer>, 65> buffers;
+
+    size_t idx = 0;
+    for (auto& buffer : buffers) {
+        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                                   BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                           BufferUsage::COMPOSER_OVERLAY,
+                                   "test");
+        Color color = colors[idx % colors.size()];
+        fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+        idx++;
+    }
+
+    // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+    // cache is working.
+    idx = 0;
+    for (auto& buffer : buffers) {
+        for (int i = 0; i < 2; i++) {
+            Transaction().setBuffer(layer, buffer).apply();
+
+            Color color = colors[idx % colors.size()];
+            auto shot = screenshot();
+            shot->expectColor(Rect(0, 0, 32, 32), color);
+            shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+        }
+        if (idx == 0) {
+            buffers[0].clear();
+        }
+        idx++;
+    }
+}
+
 TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(
@@ -2623,143 +2734,6 @@
     Transaction().setSidebandStream(layer, nullptr).apply();
 }
 
-TEST_F(LayerTransactionTest, CacheBuffer_BufferState) {
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-
-    int32_t bufferId = -1;
-    ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
-    ASSERT_GE(bufferId, 0);
-
-    ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-}
-
-TEST_F(LayerTransactionTest, CacheBuffers_BufferState) {
-    std::vector<int32_t> bufferIds;
-    int32_t bufferCount = 20;
-
-    for (int i = 0; i < bufferCount; i++) {
-        sp<GraphicBuffer> buffer =
-                new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                                  BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                          BufferUsage::COMPOSER_OVERLAY,
-                                  "test");
-        int32_t bufferId = -1;
-        ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
-        if (bufferId < 0) {
-            EXPECT_GE(bufferId, 0);
-            break;
-        }
-        bufferIds.push_back(bufferId);
-    }
-
-    for (int32_t bufferId : bufferIds) {
-        ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-    }
-}
-
-TEST_F(LayerTransactionTest, CacheBufferInvalid_BufferState) {
-    sp<GraphicBuffer> buffer = nullptr;
-
-    int32_t bufferId = -1;
-    ASSERT_NE(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
-    ASSERT_LT(bufferId, 0);
-}
-
-TEST_F(LayerTransactionTest, UncacheBufferTwice_BufferState) {
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-
-    int32_t bufferId = -1;
-    ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
-    ASSERT_GE(bufferId, 0);
-
-    ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-    mClient->uncacheBuffer(bufferId);
-}
-
-TEST_F(LayerTransactionTest, UncacheBufferInvalidId_BufferState) {
-    mClient->uncacheBuffer(-1);
-    mClient->uncacheBuffer(0);
-    mClient->uncacheBuffer(1);
-    mClient->uncacheBuffer(5);
-    mClient->uncacheBuffer(1000);
-}
-
-TEST_F(LayerTransactionTest, SetCachedBuffer_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-
-    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
-    int32_t bufferId = -1;
-    ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
-    ASSERT_GE(bufferId, 0);
-
-    Transaction().setCachedBuffer(layer, bufferId).apply();
-
-    auto shot = screenshot();
-    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-
-    ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-}
-
-TEST_F(LayerTransactionTest, SetCachedBufferDelayed_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    sp<GraphicBuffer> cachedBuffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-    int32_t bufferId = -1;
-    ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(cachedBuffer, &bufferId));
-    ASSERT_GE(bufferId, 0);
-
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::BLUE);
-    Transaction().setBuffer(layer, buffer).apply();
-    {
-        SCOPED_TRACE("Uncached buffer");
-
-        auto shot = screenshot();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
-        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-    }
-
-    fillGraphicBufferColor(cachedBuffer, Rect(0, 0, 32, 32), Color::RED);
-    Transaction().setCachedBuffer(layer, bufferId).apply();
-    {
-        SCOPED_TRACE("Cached buffer");
-
-        auto shot = screenshot();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-    }
-
-    ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
-}
-
 TEST_F(LayerTransactionTest, ReparentToSelf) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));