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