xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/ClientCache.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2019 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*38e8c45fSAndroid Build Coastguard Worker #undef LOG_TAG
19*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "ClientCache"
20*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
21*38e8c45fSAndroid Build Coastguard Worker 
22*38e8c45fSAndroid Build Coastguard Worker #include <cinttypes>
23*38e8c45fSAndroid Build Coastguard Worker 
24*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <common/trace.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <renderengine/impl/ExternalTexture.h>
27*38e8c45fSAndroid Build Coastguard Worker 
28*38e8c45fSAndroid Build Coastguard Worker #include "ClientCache.h"
29*38e8c45fSAndroid Build Coastguard Worker 
30*38e8c45fSAndroid Build Coastguard Worker namespace android {
31*38e8c45fSAndroid Build Coastguard Worker 
32*38e8c45fSAndroid Build Coastguard Worker ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache);
33*38e8c45fSAndroid Build Coastguard Worker 
ClientCache()34*38e8c45fSAndroid Build Coastguard Worker ClientCache::ClientCache() : mDeathRecipient(sp<CacheDeathRecipient>::make()) {}
35*38e8c45fSAndroid Build Coastguard Worker 
getBuffer(const client_cache_t & cacheId,ClientCacheBuffer ** outClientCacheBuffer)36*38e8c45fSAndroid Build Coastguard Worker bool ClientCache::getBuffer(const client_cache_t& cacheId,
37*38e8c45fSAndroid Build Coastguard Worker                             ClientCacheBuffer** outClientCacheBuffer) {
38*38e8c45fSAndroid Build Coastguard Worker     auto& [processToken, id] = cacheId;
39*38e8c45fSAndroid Build Coastguard Worker     if (processToken == nullptr) {
40*38e8c45fSAndroid Build Coastguard Worker         ALOGE_AND_TRACE("ClientCache::getBuffer - invalid (nullptr) process token");
41*38e8c45fSAndroid Build Coastguard Worker         return false;
42*38e8c45fSAndroid Build Coastguard Worker     }
43*38e8c45fSAndroid Build Coastguard Worker     auto it = mBuffers.find(processToken);
44*38e8c45fSAndroid Build Coastguard Worker     if (it == mBuffers.end()) {
45*38e8c45fSAndroid Build Coastguard Worker         ALOGE_AND_TRACE("ClientCache::getBuffer - invalid process token");
46*38e8c45fSAndroid Build Coastguard Worker         return false;
47*38e8c45fSAndroid Build Coastguard Worker     }
48*38e8c45fSAndroid Build Coastguard Worker 
49*38e8c45fSAndroid Build Coastguard Worker     auto& processBuffers = it->second.second;
50*38e8c45fSAndroid Build Coastguard Worker 
51*38e8c45fSAndroid Build Coastguard Worker     auto bufItr = processBuffers.find(id);
52*38e8c45fSAndroid Build Coastguard Worker     if (bufItr == processBuffers.end()) {
53*38e8c45fSAndroid Build Coastguard Worker         ALOGE_AND_TRACE("ClientCache::getBuffer - invalid buffer id");
54*38e8c45fSAndroid Build Coastguard Worker         return false;
55*38e8c45fSAndroid Build Coastguard Worker     }
56*38e8c45fSAndroid Build Coastguard Worker 
57*38e8c45fSAndroid Build Coastguard Worker     ClientCacheBuffer& buf = bufItr->second;
58*38e8c45fSAndroid Build Coastguard Worker     *outClientCacheBuffer = &buf;
59*38e8c45fSAndroid Build Coastguard Worker     return true;
60*38e8c45fSAndroid Build Coastguard Worker }
61*38e8c45fSAndroid Build Coastguard Worker 
62*38e8c45fSAndroid Build Coastguard Worker base::expected<std::shared_ptr<renderengine::ExternalTexture>, ClientCache::AddError>
add(const client_cache_t & cacheId,const sp<GraphicBuffer> & buffer)63*38e8c45fSAndroid Build Coastguard Worker ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
64*38e8c45fSAndroid Build Coastguard Worker     auto& [processToken, id] = cacheId;
65*38e8c45fSAndroid Build Coastguard Worker     if (processToken == nullptr) {
66*38e8c45fSAndroid Build Coastguard Worker         ALOGE_AND_TRACE("ClientCache::add - invalid (nullptr) process token");
67*38e8c45fSAndroid Build Coastguard Worker         return base::unexpected(AddError::Unspecified);
68*38e8c45fSAndroid Build Coastguard Worker     }
69*38e8c45fSAndroid Build Coastguard Worker 
70*38e8c45fSAndroid Build Coastguard Worker     if (!buffer) {
71*38e8c45fSAndroid Build Coastguard Worker         ALOGE_AND_TRACE("ClientCache::add - invalid (nullptr) buffer");
72*38e8c45fSAndroid Build Coastguard Worker         return base::unexpected(AddError::Unspecified);
73*38e8c45fSAndroid Build Coastguard Worker     }
74*38e8c45fSAndroid Build Coastguard Worker 
75*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
76*38e8c45fSAndroid Build Coastguard Worker     sp<IBinder> token;
77*38e8c45fSAndroid Build Coastguard Worker 
78*38e8c45fSAndroid Build Coastguard Worker     // If this is a new process token, set a death recipient. If the client process dies, we will
79*38e8c45fSAndroid Build Coastguard Worker     // get a callback through binderDied.
80*38e8c45fSAndroid Build Coastguard Worker     auto it = mBuffers.find(processToken);
81*38e8c45fSAndroid Build Coastguard Worker     if (it == mBuffers.end()) {
82*38e8c45fSAndroid Build Coastguard Worker         token = processToken.promote();
83*38e8c45fSAndroid Build Coastguard Worker         if (!token) {
84*38e8c45fSAndroid Build Coastguard Worker             ALOGE_AND_TRACE("ClientCache::add - invalid token");
85*38e8c45fSAndroid Build Coastguard Worker             return base::unexpected(AddError::Unspecified);
86*38e8c45fSAndroid Build Coastguard Worker         }
87*38e8c45fSAndroid Build Coastguard Worker 
88*38e8c45fSAndroid Build Coastguard Worker         // Only call linkToDeath if not a local binder
89*38e8c45fSAndroid Build Coastguard Worker         if (token->localBinder() == nullptr) {
90*38e8c45fSAndroid Build Coastguard Worker             status_t err = token->linkToDeath(mDeathRecipient);
91*38e8c45fSAndroid Build Coastguard Worker             if (err != NO_ERROR) {
92*38e8c45fSAndroid Build Coastguard Worker                 ALOGE_AND_TRACE("ClientCache::add - could not link to death");
93*38e8c45fSAndroid Build Coastguard Worker                 return base::unexpected(AddError::Unspecified);
94*38e8c45fSAndroid Build Coastguard Worker             }
95*38e8c45fSAndroid Build Coastguard Worker         }
96*38e8c45fSAndroid Build Coastguard Worker         auto [itr, success] =
97*38e8c45fSAndroid Build Coastguard Worker                 mBuffers.emplace(processToken,
98*38e8c45fSAndroid Build Coastguard Worker                                  std::make_pair(token,
99*38e8c45fSAndroid Build Coastguard Worker                                                 std::unordered_map<uint64_t, ClientCacheBuffer>()));
100*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(!success, "failed to insert new process into client cache");
101*38e8c45fSAndroid Build Coastguard Worker         it = itr;
102*38e8c45fSAndroid Build Coastguard Worker     }
103*38e8c45fSAndroid Build Coastguard Worker 
104*38e8c45fSAndroid Build Coastguard Worker     auto& processBuffers = it->second.second;
105*38e8c45fSAndroid Build Coastguard Worker 
106*38e8c45fSAndroid Build Coastguard Worker     if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
107*38e8c45fSAndroid Build Coastguard Worker         ALOGE_AND_TRACE("ClientCache::add - cache is full");
108*38e8c45fSAndroid Build Coastguard Worker         return base::unexpected(AddError::CacheFull);
109*38e8c45fSAndroid Build Coastguard Worker     }
110*38e8c45fSAndroid Build Coastguard Worker 
111*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr,
112*38e8c45fSAndroid Build Coastguard Worker                         "Attempted to build the ClientCache before a RenderEngine instance was "
113*38e8c45fSAndroid Build Coastguard Worker                         "ready!");
114*38e8c45fSAndroid Build Coastguard Worker 
115*38e8c45fSAndroid Build Coastguard Worker     return (processBuffers[id].buffer = std::make_shared<
116*38e8c45fSAndroid Build Coastguard Worker                     renderengine::impl::ExternalTexture>(buffer, *mRenderEngine,
117*38e8c45fSAndroid Build Coastguard Worker                                                          renderengine::impl::ExternalTexture::
118*38e8c45fSAndroid Build Coastguard Worker                                                                  Usage::READABLE));
119*38e8c45fSAndroid Build Coastguard Worker }
120*38e8c45fSAndroid Build Coastguard Worker 
erase(const client_cache_t & cacheId)121*38e8c45fSAndroid Build Coastguard Worker sp<GraphicBuffer> ClientCache::erase(const client_cache_t& cacheId) {
122*38e8c45fSAndroid Build Coastguard Worker     sp<GraphicBuffer> buffer;
123*38e8c45fSAndroid Build Coastguard Worker     auto& [processToken, id] = cacheId;
124*38e8c45fSAndroid Build Coastguard Worker     std::vector<sp<ErasedRecipient>> pendingErase;
125*38e8c45fSAndroid Build Coastguard Worker     {
126*38e8c45fSAndroid Build Coastguard Worker         std::lock_guard lock(mMutex);
127*38e8c45fSAndroid Build Coastguard Worker         ClientCacheBuffer* buf = nullptr;
128*38e8c45fSAndroid Build Coastguard Worker         if (!getBuffer(cacheId, &buf)) {
129*38e8c45fSAndroid Build Coastguard Worker             ALOGE("failed to erase buffer, could not retrieve buffer");
130*38e8c45fSAndroid Build Coastguard Worker             return nullptr;
131*38e8c45fSAndroid Build Coastguard Worker         }
132*38e8c45fSAndroid Build Coastguard Worker 
133*38e8c45fSAndroid Build Coastguard Worker         buffer = buf->buffer->getBuffer();
134*38e8c45fSAndroid Build Coastguard Worker 
135*38e8c45fSAndroid Build Coastguard Worker         for (auto& recipient : buf->recipients) {
136*38e8c45fSAndroid Build Coastguard Worker             sp<ErasedRecipient> erasedRecipient = recipient.promote();
137*38e8c45fSAndroid Build Coastguard Worker             if (erasedRecipient) {
138*38e8c45fSAndroid Build Coastguard Worker                 pendingErase.push_back(erasedRecipient);
139*38e8c45fSAndroid Build Coastguard Worker             }
140*38e8c45fSAndroid Build Coastguard Worker         }
141*38e8c45fSAndroid Build Coastguard Worker 
142*38e8c45fSAndroid Build Coastguard Worker         mBuffers[processToken].second.erase(id);
143*38e8c45fSAndroid Build Coastguard Worker     }
144*38e8c45fSAndroid Build Coastguard Worker 
145*38e8c45fSAndroid Build Coastguard Worker     for (auto& recipient : pendingErase) {
146*38e8c45fSAndroid Build Coastguard Worker         recipient->bufferErased(cacheId);
147*38e8c45fSAndroid Build Coastguard Worker     }
148*38e8c45fSAndroid Build Coastguard Worker     return buffer;
149*38e8c45fSAndroid Build Coastguard Worker }
150*38e8c45fSAndroid Build Coastguard Worker 
get(const client_cache_t & cacheId)151*38e8c45fSAndroid Build Coastguard Worker std::shared_ptr<renderengine::ExternalTexture> ClientCache::get(const client_cache_t& cacheId) {
152*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
153*38e8c45fSAndroid Build Coastguard Worker 
154*38e8c45fSAndroid Build Coastguard Worker     ClientCacheBuffer* buf = nullptr;
155*38e8c45fSAndroid Build Coastguard Worker     if (!getBuffer(cacheId, &buf)) {
156*38e8c45fSAndroid Build Coastguard Worker         ALOGE("failed to get buffer, could not retrieve buffer");
157*38e8c45fSAndroid Build Coastguard Worker         return nullptr;
158*38e8c45fSAndroid Build Coastguard Worker     }
159*38e8c45fSAndroid Build Coastguard Worker 
160*38e8c45fSAndroid Build Coastguard Worker     return buf->buffer;
161*38e8c45fSAndroid Build Coastguard Worker }
162*38e8c45fSAndroid Build Coastguard Worker 
registerErasedRecipient(const client_cache_t & cacheId,const wp<ErasedRecipient> & recipient)163*38e8c45fSAndroid Build Coastguard Worker bool ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
164*38e8c45fSAndroid Build Coastguard Worker                                           const wp<ErasedRecipient>& recipient) {
165*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
166*38e8c45fSAndroid Build Coastguard Worker 
167*38e8c45fSAndroid Build Coastguard Worker     ClientCacheBuffer* buf = nullptr;
168*38e8c45fSAndroid Build Coastguard Worker     if (!getBuffer(cacheId, &buf)) {
169*38e8c45fSAndroid Build Coastguard Worker         ALOGV("failed to register erased recipient, could not retrieve buffer");
170*38e8c45fSAndroid Build Coastguard Worker         return false;
171*38e8c45fSAndroid Build Coastguard Worker     }
172*38e8c45fSAndroid Build Coastguard Worker     buf->recipients.insert(recipient);
173*38e8c45fSAndroid Build Coastguard Worker     return true;
174*38e8c45fSAndroid Build Coastguard Worker }
175*38e8c45fSAndroid Build Coastguard Worker 
unregisterErasedRecipient(const client_cache_t & cacheId,const wp<ErasedRecipient> & recipient)176*38e8c45fSAndroid Build Coastguard Worker void ClientCache::unregisterErasedRecipient(const client_cache_t& cacheId,
177*38e8c45fSAndroid Build Coastguard Worker                                             const wp<ErasedRecipient>& recipient) {
178*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
179*38e8c45fSAndroid Build Coastguard Worker 
180*38e8c45fSAndroid Build Coastguard Worker     ClientCacheBuffer* buf = nullptr;
181*38e8c45fSAndroid Build Coastguard Worker     if (!getBuffer(cacheId, &buf)) {
182*38e8c45fSAndroid Build Coastguard Worker         ALOGE("failed to unregister erased recipient");
183*38e8c45fSAndroid Build Coastguard Worker         return;
184*38e8c45fSAndroid Build Coastguard Worker     }
185*38e8c45fSAndroid Build Coastguard Worker 
186*38e8c45fSAndroid Build Coastguard Worker     buf->recipients.erase(recipient);
187*38e8c45fSAndroid Build Coastguard Worker }
188*38e8c45fSAndroid Build Coastguard Worker 
removeProcess(const wp<IBinder> & processToken)189*38e8c45fSAndroid Build Coastguard Worker void ClientCache::removeProcess(const wp<IBinder>& processToken) {
190*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::pair<sp<ErasedRecipient>, client_cache_t>> pendingErase;
191*38e8c45fSAndroid Build Coastguard Worker     {
192*38e8c45fSAndroid Build Coastguard Worker         if (processToken == nullptr) {
193*38e8c45fSAndroid Build Coastguard Worker             ALOGE("failed to remove process, invalid (nullptr) process token");
194*38e8c45fSAndroid Build Coastguard Worker             return;
195*38e8c45fSAndroid Build Coastguard Worker         }
196*38e8c45fSAndroid Build Coastguard Worker         std::lock_guard lock(mMutex);
197*38e8c45fSAndroid Build Coastguard Worker         auto itr = mBuffers.find(processToken);
198*38e8c45fSAndroid Build Coastguard Worker         if (itr == mBuffers.end()) {
199*38e8c45fSAndroid Build Coastguard Worker             ALOGE("failed to remove process, could not find process");
200*38e8c45fSAndroid Build Coastguard Worker             return;
201*38e8c45fSAndroid Build Coastguard Worker         }
202*38e8c45fSAndroid Build Coastguard Worker 
203*38e8c45fSAndroid Build Coastguard Worker         for (auto& [id, clientCacheBuffer] : itr->second.second) {
204*38e8c45fSAndroid Build Coastguard Worker             client_cache_t cacheId = {processToken, id};
205*38e8c45fSAndroid Build Coastguard Worker             for (auto& recipient : clientCacheBuffer.recipients) {
206*38e8c45fSAndroid Build Coastguard Worker                 sp<ErasedRecipient> erasedRecipient = recipient.promote();
207*38e8c45fSAndroid Build Coastguard Worker                 if (erasedRecipient) {
208*38e8c45fSAndroid Build Coastguard Worker                     pendingErase.emplace_back(erasedRecipient, cacheId);
209*38e8c45fSAndroid Build Coastguard Worker                 }
210*38e8c45fSAndroid Build Coastguard Worker             }
211*38e8c45fSAndroid Build Coastguard Worker         }
212*38e8c45fSAndroid Build Coastguard Worker         mBuffers.erase(itr);
213*38e8c45fSAndroid Build Coastguard Worker     }
214*38e8c45fSAndroid Build Coastguard Worker 
215*38e8c45fSAndroid Build Coastguard Worker     for (auto& [recipient, cacheId] : pendingErase) {
216*38e8c45fSAndroid Build Coastguard Worker         recipient->bufferErased(cacheId);
217*38e8c45fSAndroid Build Coastguard Worker     }
218*38e8c45fSAndroid Build Coastguard Worker }
219*38e8c45fSAndroid Build Coastguard Worker 
binderDied(const wp<IBinder> & who)220*38e8c45fSAndroid Build Coastguard Worker void ClientCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) {
221*38e8c45fSAndroid Build Coastguard Worker     ClientCache::getInstance().removeProcess(who);
222*38e8c45fSAndroid Build Coastguard Worker }
223*38e8c45fSAndroid Build Coastguard Worker 
dump(std::string & result)224*38e8c45fSAndroid Build Coastguard Worker void ClientCache::dump(std::string& result) {
225*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock(mMutex);
226*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [_, cache] : mBuffers) {
227*38e8c45fSAndroid Build Coastguard Worker         base::StringAppendF(&result, " Cache owner: %p\n", cache.first.get());
228*38e8c45fSAndroid Build Coastguard Worker 
229*38e8c45fSAndroid Build Coastguard Worker         for (const auto& [id, entry] : cache.second) {
230*38e8c45fSAndroid Build Coastguard Worker             const auto& buffer = entry.buffer->getBuffer();
231*38e8c45fSAndroid Build Coastguard Worker             base::StringAppendF(&result, "\tID: %" PRIu64 ", size: %ux%u\n", id, buffer->getWidth(),
232*38e8c45fSAndroid Build Coastguard Worker                                 buffer->getHeight());
233*38e8c45fSAndroid Build Coastguard Worker         }
234*38e8c45fSAndroid Build Coastguard Worker     }
235*38e8c45fSAndroid Build Coastguard Worker }
236*38e8c45fSAndroid Build Coastguard Worker 
237*38e8c45fSAndroid Build Coastguard Worker } // namespace android
238