blast: drop buffer from SF's cache when destroyed
When an app drops its reference to an AHardwareBuffer, the buffer
should be removed from the client and SurfaceFlinger caches.
Ideally, both caches would have wp to the buffer and the buffer
would automatically be removed from the cache.
Unfortunately, GraphicBuffers are refcounted per process. If SurfaceFlinger
just has a wp to the GraphicBuffer, the buffer's destructor will
be called and SurfaceFlinger will lose access to the buffer.
SurfaceFlinger can't just hold onto a sp to the buffer because
then the buffer wouldn't be destoryed when the app drops its reference.
Instead, when the app process drops its last strong reference,
GraphicBuffer will send a callback to the client side cache.
The cache will send a Transaction to SurfaceFlinger to drop its sp
to the buffer.
Bug: 127689853
Test: SurfaceFlinger_test
Change-Id: I2182578ed33d7c731945cb88cd1decb2892266b0
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 247dc8d..bc63d31 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -68,7 +68,8 @@
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
const InputWindowCommands& commands,
- int64_t desiredPresentTime) {
+ int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -86,6 +87,8 @@
data.writeStrongBinder(applyToken);
commands.write(data);
data.writeInt64(desiredPresentTime);
+ data.writeStrongBinder(uncacheBuffer.token);
+ data.writeUint64(uncacheBuffer.cacheId);
remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
}
@@ -970,8 +973,13 @@
inputWindowCommands.read(data);
int64_t desiredPresentTime = data.readInt64();
+
+ cached_buffer_t uncachedBuffer;
+ uncachedBuffer.token = data.readStrongBinder();
+ uncachedBuffer.cacheId = data.readUint64();
+
setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
- desiredPresentTime);
+ desiredPresentTime, uncachedBuffer);
return NO_ERROR;
}
case BOOT_FINISHED: {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 84ba644..f6ca9e8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -95,7 +95,7 @@
}
output.writeStrongBinder(cachedBuffer.token);
- output.writeInt32(cachedBuffer.bufferId);
+ output.writeUint64(cachedBuffer.cacheId);
output.writeParcelable(metadata);
output.writeFloat(bgColorAlpha);
@@ -173,7 +173,7 @@
}
cachedBuffer.token = input.readStrongBinder();
- cachedBuffer.bufferId = input.readInt32();
+ cachedBuffer.cacheId = input.readUint64();
input.readParcelable(&metadata);
bgColorAlpha = input.readFloat();
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b0e8275..39cd62f 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -233,6 +233,8 @@
// ---------------------------------------------------------------------------
+void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId);
+
class BufferCache : public Singleton<BufferCache> {
public:
BufferCache() : token(new BBinder()) {}
@@ -241,77 +243,57 @@
return IInterface::asBinder(TransactionCompletedListener::getIInstance());
}
- int32_t getId(const sp<GraphicBuffer>& buffer) {
+ status_t getCacheId(const sp<GraphicBuffer>& buffer, uint64_t* cacheId) {
std::lock_guard<std::mutex> lock(mMutex);
- auto itr = mBuffers.find(buffer);
+ auto itr = mBuffers.find(buffer->getId());
if (itr == mBuffers.end()) {
- return -1;
+ return BAD_VALUE;
}
- itr->second.counter = getCounter();
- return itr->second.id;
+ itr->second = getCounter();
+ *cacheId = buffer->getId();
+ return NO_ERROR;
}
- int32_t cache(const sp<GraphicBuffer>& buffer) {
+ uint64_t cache(const sp<GraphicBuffer>& buffer) {
std::lock_guard<std::mutex> lock(mMutex);
- int32_t bufferId = getNextAvailableId();
+ if (mBuffers.size() >= BUFFER_CACHE_MAX_SIZE) {
+ evictLeastRecentlyUsedBuffer();
+ }
- mBuffers[buffer].id = bufferId;
- mBuffers[buffer].counter = getCounter();
- return bufferId;
+ buffer->addDeathCallback(bufferCacheCallback, nullptr);
+
+ mBuffers[buffer->getId()] = getCounter();
+ return buffer->getId();
+ }
+
+ void uncache(uint64_t cacheId) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ uncacheLocked(cacheId);
+ }
+
+ void uncacheLocked(uint64_t cacheId) REQUIRES(mMutex) {
+ mBuffers.erase(cacheId);
+ SurfaceComposerClient::doUncacheBufferTransaction(cacheId);
}
private:
- int32_t evictDestroyedBuffer() REQUIRES(mMutex) {
+ void evictLeastRecentlyUsedBuffer() 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;
+ uint64_t minCounter = itr->second;
auto minBuffer = itr;
itr++;
while (itr != mBuffers.end()) {
- uint64_t counter = itr->second.counter;
+ uint64_t counter = itr->second;
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();
+ uncacheLocked(minBuffer->first);
}
uint64_t getCounter() REQUIRES(mMutex) {
@@ -319,18 +301,8 @@
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);
+ std::map<uint64_t /*Cache id*/, uint64_t /*counter*/> mBuffers GUARDED_BY(mMutex);
// Used by ISurfaceComposer to identify which process is sending the cached buffer.
sp<IBinder> token;
@@ -338,6 +310,11 @@
ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache);
+void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId) {
+ // GraphicBuffer id's are used as the cache ids.
+ BufferCache::getInstance().uncache(graphicBufferId);
+}
+
// ---------------------------------------------------------------------------
SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
@@ -385,6 +362,9 @@
mInputWindowCommands.merge(other.mInputWindowCommands);
other.mInputWindowCommands.clear();
+ mContainsBuffer = other.mContainsBuffer;
+ other.mContainsBuffer = false;
+
return *this;
}
@@ -401,7 +381,50 @@
s.state.parentHandleForChild = nullptr;
composerStates.add(s);
- sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1);
+ sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1, {});
+}
+
+void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+ cached_buffer_t uncacheBuffer;
+ uncacheBuffer.token = BufferCache::getInstance().getToken();
+ uncacheBuffer.cacheId = cacheId;
+
+ sf->setTransactionState({}, {}, 0, nullptr, {}, -1, uncacheBuffer);
+}
+
+void SurfaceComposerClient::Transaction::cacheBuffers() {
+ if (!mContainsBuffer) {
+ return;
+ }
+
+ size_t count = 0;
+ for (auto& [sc, cs] : mComposerStates) {
+ layer_state_t* s = getLayerState(sc);
+ if (!(s->what & layer_state_t::eBufferChanged)) {
+ continue;
+ }
+
+ uint64_t cacheId = 0;
+ status_t ret = BufferCache::getInstance().getCacheId(s->buffer, &cacheId);
+ if (ret == NO_ERROR) {
+ s->what &= ~static_cast<uint32_t>(layer_state_t::eBufferChanged);
+ s->buffer = nullptr;
+ } else {
+ cacheId = BufferCache::getInstance().cache(s->buffer);
+ }
+ s->what |= layer_state_t::eCachedBufferChanged;
+ s->cachedBuffer.token = BufferCache::getInstance().getToken();
+ s->cachedBuffer.cacheId = 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
+ count++;
+ if (count >= BUFFER_CACHE_MAX_SIZE) {
+ break;
+ }
+ }
}
status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
@@ -437,6 +460,8 @@
}
mListenerCallbacks.clear();
+ cacheBuffers();
+
Vector<ComposerState> composerStates;
Vector<DisplayState> displayStates;
uint32_t flags = 0;
@@ -468,7 +493,8 @@
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
- mDesiredPresentTime);
+ mDesiredPresentTime,
+ {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/);
mInputWindowCommands.clear();
mStatus = NO_ERROR;
return NO_ERROR;
@@ -882,20 +908,12 @@
mStatus = BAD_INDEX;
return *this;
}
-
- int32_t bufferId = BufferCache::getInstance().getId(buffer);
- if (bufferId < 0) {
- bufferId = BufferCache::getInstance().cache(buffer);
-
- s->what |= layer_state_t::eBufferChanged;
- s->buffer = buffer;
- }
-
- s->what |= layer_state_t::eCachedBufferChanged;
- s->cachedBuffer.token = BufferCache::getInstance().getToken();
- s->cachedBuffer.bufferId = bufferId;
+ s->what |= layer_state_t::eBufferChanged;
+ s->buffer = buffer;
registerSurfaceControlForCallback(sc);
+
+ mContainsBuffer = true;
return *this;
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 8f54fee..0ef5b39 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -40,6 +40,7 @@
namespace android {
// ----------------------------------------------------------------------------
+struct cached_buffer_t;
struct ComposerState;
struct DisplayState;
struct DisplayInfo;
@@ -131,7 +132,8 @@
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
- int64_t desiredPresentTime) = 0;
+ int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer) = 0;
/* signal that we're done booting.
* Requires ACCESS_SURFACE_FLINGER permission
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 35e795c..77bf8f1 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -41,6 +41,11 @@
class Parcel;
class ISurfaceComposerClient;
+struct cached_buffer_t {
+ sp<IBinder> token = nullptr;
+ uint64_t cacheId;
+};
+
/*
* Used to communicate layer information between SurfaceFlinger and its clients.
*/
@@ -133,10 +138,6 @@
float dtdy{0};
float dsdy{0};
};
- struct cached_buffer_t {
- sp<IBinder> token = nullptr;
- int32_t bufferId = -1;
- };
sp<IBinder> surface;
uint64_t what;
float x;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 39d6d13..593a5e7 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -165,6 +165,12 @@
static void doDropReferenceTransaction(const sp<IBinder>& handle,
const sp<ISurfaceComposerClient>& client);
+ /**
+ * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
+ * in order with other transactions that use buffers.
+ */
+ static void doUncacheBufferTransaction(uint64_t cacheId);
+
// Queries whether a given display is wide color display.
static status_t isWideColorDisplay(const sp<IBinder>& display, bool* outIsWideColorDisplay);
@@ -279,6 +285,9 @@
bool mAnimation = false;
bool mEarlyWakeup = false;
+ // Indicates that the Transaction contains a buffer that should be cached
+ bool mContainsBuffer = false;
+
// mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
// to be presented. When it is not possible to present at exactly that time, it will be
// presented after the time has passed.
@@ -297,6 +306,7 @@
layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
DisplayState& getDisplayState(const sp<IBinder>& token);
+ void cacheBuffers();
void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
public:
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 06fe86c..94b669d 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -560,7 +560,8 @@
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
const sp<IBinder>& /*applyToken*/,
const InputWindowCommands& /*inputWindowCommands*/,
- int64_t /*desiredPresentTime*/) override {}
+ int64_t /*desiredPresentTime*/,
+ const cached_buffer_t& /*cachedBuffer*/) override {}
void bootFinished() override {}
bool authenticateSurfaceTexture(
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index f800627..637a9cf 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -133,6 +133,9 @@
if (handle) {
free_handle();
}
+ for (auto& [callback, context] : mDeathCallbacks) {
+ callback(context, mId);
+ }
}
void GraphicBuffer::free_handle()
@@ -534,6 +537,10 @@
return NO_ERROR;
}
+void GraphicBuffer::addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context) {
+ mDeathCallbacks.emplace_back(deathCallback, context);
+}
+
#ifndef LIBUI_IN_VNDK
bool GraphicBuffer::isBufferHubBuffer() const {
return mBufferHubBuffer != nullptr;
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 1c88777..f86ca59 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -21,6 +21,8 @@
#include <sys/types.h>
#include <string>
+#include <utility>
+#include <vector>
#include <android/hardware_buffer.h>
#include <ui/ANativeObjectBase.h>
@@ -42,6 +44,8 @@
class GraphicBufferMapper;
+using GraphicBufferDeathCallback = std::function<void(void* /*context*/, uint64_t bufferId)>;
+
// ===========================================================================
// GraphicBuffer
// ===========================================================================
@@ -219,6 +223,8 @@
return mBufferMapper.getMapperVersion();
}
+ void addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context);
+
#ifndef LIBUI_IN_VNDK
// Returns whether this GraphicBuffer is backed by BufferHubBuffer.
bool isBufferHubBuffer() const;
@@ -280,6 +286,20 @@
// IGBP::setGenerationNumber), attempts to attach the buffer will fail.
uint32_t mGenerationNumber;
+ // Send a callback when a GraphicBuffer dies.
+ //
+ // This is used for BufferStateLayer caching. GraphicBuffers are refcounted per process. When
+ // A GraphicBuffer doesn't have any more sp<> in a process, it is destroyed. This causes
+ // problems when trying to implicitcly cache across process boundaries. Ideally, both sides
+ // of the cache would hold onto wp<> references. When an app dropped its sp<>, the GraphicBuffer
+ // would be destroyed. Unfortunately, when SurfaceFlinger has only a wp<> reference to the
+ // GraphicBuffer, it immediately goes out of scope in the SurfaceFlinger process. SurfaceFlinger
+ // must hold onto a sp<> to the buffer. When the GraphicBuffer goes out of scope in the app's
+ // process, the client side cache will get this callback. It erases the buffer from its cache
+ // and informs SurfaceFlinger that it should drop its strong pointer reference to the buffer.
+ std::vector<std::pair<GraphicBufferDeathCallback, void* /*mDeathCallbackContext*/>>
+ mDeathCallbacks;
+
#ifndef LIBUI_IN_VNDK
// Stores a BufferHubBuffer that handles buffer signaling, identification.
std::unique_ptr<BufferHubBuffer> mBufferHubBuffer;
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
index cb02d16..51ca45c 100644
--- a/services/surfaceflinger/BufferStateLayerCache.cpp
+++ b/services/surfaceflinger/BufferStateLayerCache.cpp
@@ -23,21 +23,14 @@
#include "BufferStateLayerCache.h"
-#define VALID_CACHE_ID(id) ((id) >= 0 || (id) < (BUFFER_CACHE_MAX_SIZE))
-
namespace android {
ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache);
BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {}
-void BufferStateLayerCache::add(sp<IBinder> processToken, int32_t id,
+void BufferStateLayerCache::add(const sp<IBinder>& processToken, uint64_t id,
const sp<GraphicBuffer>& buffer) {
- if (!VALID_CACHE_ID(id)) {
- ALOGE("failed to cache buffer: invalid buffer id");
- return;
- }
-
if (!processToken) {
ALOGE("failed to cache buffer: invalid process token");
return;
@@ -61,15 +54,33 @@
}
auto& processBuffers = mBuffers[processToken];
+
+ if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
+ ALOGE("failed to cache buffer: cache is full");
+ return;
+ }
+
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;
+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;
@@ -82,8 +93,8 @@
return nullptr;
}
- if (id >= itr->second.size()) {
- ALOGE("failed to get buffer: id outside the bounds of the cache");
+ if (itr->second.find(id) == itr->second.end()) {
+ ALOGE("failed to get buffer: buffer not found");
return nullptr;
}
diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h
index ede3feb..415c09c 100644
--- a/services/surfaceflinger/BufferStateLayerCache.h
+++ b/services/surfaceflinger/BufferStateLayerCache.h
@@ -34,14 +34,16 @@
public:
BufferStateLayerCache();
- void add(sp<IBinder> processToken, int32_t id, const sp<GraphicBuffer>& buffer);
- sp<GraphicBuffer> get(sp<IBinder> processToken, int32_t id);
+ 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::array<sp<GraphicBuffer>, BUFFER_CACHE_MAX_SIZE>>
+ std::map<wp<IBinder> /*caching process*/, std::map<uint64_t /*Cache id*/, sp<GraphicBuffer>>>
mBuffers GUARDED_BY(mMutex);
class CacheDeathRecipient : public IBinder::DeathRecipient {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 55fcb01..547f30f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3508,13 +3508,15 @@
auto& [applyToken, transactionQueue] = *it;
while (!transactionQueue.empty()) {
- const auto& [states, displays, flags, desiredPresentTime, postTime, privileged] =
- transactionQueue.front();
+ const auto&
+ [states, displays, flags, desiredPresentTime, uncacheBuffer, postTime,
+ privileged] = transactionQueue.front();
if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
break;
}
applyTransactionState(states, displays, flags, mPendingInputWindowCommands,
- desiredPresentTime, postTime, privileged, /*isMainThread*/ true);
+ desiredPresentTime, uncacheBuffer, postTime, privileged,
+ /*isMainThread*/ true);
transactionQueue.pop();
}
@@ -3571,7 +3573,8 @@
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
- int64_t desiredPresentTime) {
+ int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer) {
ATRACE_CALL();
const int64_t postTime = systemTime();
@@ -3588,20 +3591,22 @@
if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
- postTime, privileged);
+ uncacheBuffer, postTime, privileged);
setTransactionFlags(eTransactionNeeded);
return;
}
applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
- postTime, privileged);
+ uncacheBuffer, postTime, privileged);
}
void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
- const int64_t desiredPresentTime, const int64_t postTime,
- bool privileged, bool isMainThread) {
+ const int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer,
+ const int64_t postTime, bool privileged,
+ bool isMainThread) {
uint32_t transactionFlags = 0;
if (flags & eAnimation) {
@@ -3636,6 +3641,10 @@
transactionFlags |= addInputWindowCommands(inputWindowCommands);
+ if (uncacheBuffer.token) {
+ BufferStateLayerCache::getInstance().erase(uncacheBuffer.token, uncacheBuffer.cacheId);
+ }
+
// If a synchronous transaction is explicitly requested without any changes, force a transaction
// anyway. This can be used as a flush mechanism for previous async transactions.
// Empty animation transaction can be used to simulate back-pressure, so also force a
@@ -3977,16 +3986,20 @@
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,
+ bool bufferChanged = what & layer_state_t::eBufferChanged;
+ bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
+ sp<GraphicBuffer> buffer;
+ if (bufferChanged && cacheIdChanged) {
+ BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.cacheId,
s.buffer);
+ buffer = s.buffer;
+ } else if (cacheIdChanged) {
+ buffer = BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
+ s.cachedBuffer.cacheId);
+ } else if (bufferChanged) {
+ buffer = s.buffer;
}
- if (what & layer_state_t::eCachedBufferChanged) {
- sp<GraphicBuffer> buffer =
- BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
- s.cachedBuffer.bufferId);
+ if (buffer) {
if (layer->setBuffer(buffer)) {
flags |= eTraversalNeeded;
layer->setPostTime(postTime);
@@ -4230,7 +4243,7 @@
d.width = 0;
d.height = 0;
displays.add(d);
- setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1);
+ setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {});
setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0776a1e..03146d6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -431,7 +431,8 @@
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
- int64_t desiredPresentTime) override;
+ int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer) override;
void bootFinished() override;
bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const override;
@@ -577,7 +578,8 @@
void applyTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
- const int64_t desiredPresentTime, const int64_t postTime,
+ const int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer, const int64_t postTime,
bool privileged, bool isMainThread = false) REQUIRES(mStateLock);
bool flushTransactionQueues();
uint32_t getTransactionFlags(uint32_t flags);
@@ -1058,11 +1060,13 @@
struct TransactionState {
TransactionState(const Vector<ComposerState>& composerStates,
const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
- int64_t desiredPresentTime, int64_t postTime, bool privileged)
+ int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer,
+ int64_t postTime, bool privileged)
: states(composerStates),
displays(displayStates),
flags(transactionFlags),
desiredPresentTime(desiredPresentTime),
+ buffer(uncacheBuffer),
postTime(postTime),
privileged(privileged) {}
@@ -1070,6 +1074,7 @@
Vector<DisplayState> displays;
uint32_t flags;
const int64_t desiredPresentTime;
+ cached_buffer_t buffer;
const int64_t postTime;
bool privileged;
};