blob: 2bd8f324e1525d35968f80a6267f8bda77f0bca8 [file] [log] [blame]
Marissa Wall947d34e2019-03-29 14:03:53 -07001/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#undef LOG_TAG
19#define LOG_TAG "ClientCache"
20#define ATRACE_TAG ATRACE_TAG_GRAPHICS
21
22#include <cinttypes>
23
Dominik Laskowski75788452021-02-09 18:51:25 -080024#include <android-base/stringprintf.h>
Patrick Williams640b7292022-10-11 19:25:06 +000025#include <gui/TraceUtils.h>
Vishnu Nairdbbe3852022-01-12 20:22:11 -080026#include <renderengine/impl/ExternalTexture.h>
Dominik Laskowski75788452021-02-09 18:51:25 -080027
Marissa Wall947d34e2019-03-29 14:03:53 -070028#include "ClientCache.h"
29
30namespace android {
31
32ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache);
33
Ady Abrahamd11bade2022-08-01 16:18:03 -070034ClientCache::ClientCache() : mDeathRecipient(sp<CacheDeathRecipient>::make()) {}
Marissa Wall947d34e2019-03-29 14:03:53 -070035
36bool ClientCache::getBuffer(const client_cache_t& cacheId,
37 ClientCacheBuffer** outClientCacheBuffer) {
38 auto& [processToken, id] = cacheId;
39 if (processToken == nullptr) {
Patrick Williams640b7292022-10-11 19:25:06 +000040 ALOGE_AND_TRACE("ClientCache::getBuffer - invalid (nullptr) process token");
Marissa Wall947d34e2019-03-29 14:03:53 -070041 return false;
42 }
43 auto it = mBuffers.find(processToken);
44 if (it == mBuffers.end()) {
Patrick Williams640b7292022-10-11 19:25:06 +000045 ALOGE_AND_TRACE("ClientCache::getBuffer - invalid process token");
Marissa Wall947d34e2019-03-29 14:03:53 -070046 return false;
47 }
48
Valerie Hau90fcc942019-11-18 11:18:57 -080049 auto& processBuffers = it->second.second;
Marissa Wall947d34e2019-03-29 14:03:53 -070050
51 auto bufItr = processBuffers.find(id);
52 if (bufItr == processBuffers.end()) {
Patrick Williams640b7292022-10-11 19:25:06 +000053 ALOGE_AND_TRACE("ClientCache::getBuffer - invalid buffer id");
Marissa Wall947d34e2019-03-29 14:03:53 -070054 return false;
55 }
56
57 ClientCacheBuffer& buf = bufItr->second;
58 *outClientCacheBuffer = &buf;
59 return true;
60}
61
Patrick Williamsf1e5df12022-10-17 21:37:42 +000062base::expected<std::shared_ptr<renderengine::ExternalTexture>, ClientCache::AddError>
63ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
Marissa Wall947d34e2019-03-29 14:03:53 -070064 auto& [processToken, id] = cacheId;
65 if (processToken == nullptr) {
Patrick Williams640b7292022-10-11 19:25:06 +000066 ALOGE_AND_TRACE("ClientCache::add - invalid (nullptr) process token");
Patrick Williamsf1e5df12022-10-17 21:37:42 +000067 return base::unexpected(AddError::Unspecified);
Marissa Wall947d34e2019-03-29 14:03:53 -070068 }
69
70 if (!buffer) {
Patrick Williams640b7292022-10-11 19:25:06 +000071 ALOGE_AND_TRACE("ClientCache::add - invalid (nullptr) buffer");
Patrick Williamsf1e5df12022-10-17 21:37:42 +000072 return base::unexpected(AddError::Unspecified);
Marissa Wall947d34e2019-03-29 14:03:53 -070073 }
74
75 std::lock_guard lock(mMutex);
76 sp<IBinder> token;
77
78 // If this is a new process token, set a death recipient. If the client process dies, we will
79 // get a callback through binderDied.
80 auto it = mBuffers.find(processToken);
81 if (it == mBuffers.end()) {
82 token = processToken.promote();
83 if (!token) {
Patrick Williams640b7292022-10-11 19:25:06 +000084 ALOGE_AND_TRACE("ClientCache::add - invalid token");
Patrick Williamsf1e5df12022-10-17 21:37:42 +000085 return base::unexpected(AddError::Unspecified);
Marissa Wall947d34e2019-03-29 14:03:53 -070086 }
87
chaviw70aa7572021-09-22 12:27:57 -050088 // Only call linkToDeath if not a local binder
89 if (token->localBinder() == nullptr) {
90 status_t err = token->linkToDeath(mDeathRecipient);
91 if (err != NO_ERROR) {
Patrick Williams640b7292022-10-11 19:25:06 +000092 ALOGE_AND_TRACE("ClientCache::add - could not link to death");
Patrick Williamsf1e5df12022-10-17 21:37:42 +000093 return base::unexpected(AddError::Unspecified);
chaviw70aa7572021-09-22 12:27:57 -050094 }
Marissa Wall947d34e2019-03-29 14:03:53 -070095 }
96 auto [itr, success] =
Valerie Hau90fcc942019-11-18 11:18:57 -080097 mBuffers.emplace(processToken,
98 std::make_pair(token,
99 std::unordered_map<uint64_t, ClientCacheBuffer>()));
Marissa Wall947d34e2019-03-29 14:03:53 -0700100 LOG_ALWAYS_FATAL_IF(!success, "failed to insert new process into client cache");
101 it = itr;
102 }
103
Valerie Hau90fcc942019-11-18 11:18:57 -0800104 auto& processBuffers = it->second.second;
Marissa Wall947d34e2019-03-29 14:03:53 -0700105
106 if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
Patrick Williams640b7292022-10-11 19:25:06 +0000107 ALOGE_AND_TRACE("ClientCache::add - cache is full");
Patrick Williamsf1e5df12022-10-17 21:37:42 +0000108 return base::unexpected(AddError::CacheFull);
Marissa Wall947d34e2019-03-29 14:03:53 -0700109 }
110
Alec Mouria90a5702021-04-16 16:36:21 +0000111 LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr,
112 "Attempted to build the ClientCache before a RenderEngine instance was "
113 "ready!");
Patrick Williamsf1e5df12022-10-17 21:37:42 +0000114
115 return (processBuffers[id].buffer = std::make_shared<
116 renderengine::impl::ExternalTexture>(buffer, *mRenderEngine,
117 renderengine::impl::ExternalTexture::
118 Usage::READABLE));
Marissa Wall947d34e2019-03-29 14:03:53 -0700119}
120
121void ClientCache::erase(const client_cache_t& cacheId) {
122 auto& [processToken, id] = cacheId;
123 std::vector<sp<ErasedRecipient>> pendingErase;
124 {
125 std::lock_guard lock(mMutex);
126 ClientCacheBuffer* buf = nullptr;
127 if (!getBuffer(cacheId, &buf)) {
128 ALOGE("failed to erase buffer, could not retrieve buffer");
129 return;
130 }
131
132 for (auto& recipient : buf->recipients) {
133 sp<ErasedRecipient> erasedRecipient = recipient.promote();
134 if (erasedRecipient) {
135 pendingErase.push_back(erasedRecipient);
136 }
137 }
138
Valerie Hau90fcc942019-11-18 11:18:57 -0800139 mBuffers[processToken].second.erase(id);
Marissa Wall947d34e2019-03-29 14:03:53 -0700140 }
141
142 for (auto& recipient : pendingErase) {
143 recipient->bufferErased(cacheId);
144 }
145}
146
Alec Mouria90a5702021-04-16 16:36:21 +0000147std::shared_ptr<renderengine::ExternalTexture> ClientCache::get(const client_cache_t& cacheId) {
Marissa Wall947d34e2019-03-29 14:03:53 -0700148 std::lock_guard lock(mMutex);
149
150 ClientCacheBuffer* buf = nullptr;
151 if (!getBuffer(cacheId, &buf)) {
152 ALOGE("failed to get buffer, could not retrieve buffer");
153 return nullptr;
154 }
155
156 return buf->buffer;
157}
158
Alec Mouri4545a8a2019-08-08 20:05:32 -0700159bool ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
Marissa Wall947d34e2019-03-29 14:03:53 -0700160 const wp<ErasedRecipient>& recipient) {
161 std::lock_guard lock(mMutex);
162
163 ClientCacheBuffer* buf = nullptr;
164 if (!getBuffer(cacheId, &buf)) {
Vishnu Nair65eafde2021-03-24 12:17:36 -0700165 ALOGV("failed to register erased recipient, could not retrieve buffer");
Alec Mouri4545a8a2019-08-08 20:05:32 -0700166 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -0700167 }
168 buf->recipients.insert(recipient);
Alec Mouri4545a8a2019-08-08 20:05:32 -0700169 return true;
Marissa Wall947d34e2019-03-29 14:03:53 -0700170}
171
172void ClientCache::unregisterErasedRecipient(const client_cache_t& cacheId,
173 const wp<ErasedRecipient>& recipient) {
174 std::lock_guard lock(mMutex);
175
176 ClientCacheBuffer* buf = nullptr;
177 if (!getBuffer(cacheId, &buf)) {
178 ALOGE("failed to unregister erased recipient");
179 return;
180 }
181
182 buf->recipients.erase(recipient);
183}
184
185void ClientCache::removeProcess(const wp<IBinder>& processToken) {
186 std::vector<std::pair<sp<ErasedRecipient>, client_cache_t>> pendingErase;
187 {
188 if (processToken == nullptr) {
189 ALOGE("failed to remove process, invalid (nullptr) process token");
190 return;
191 }
192 std::lock_guard lock(mMutex);
193 auto itr = mBuffers.find(processToken);
194 if (itr == mBuffers.end()) {
195 ALOGE("failed to remove process, could not find process");
196 return;
197 }
198
Valerie Hau90fcc942019-11-18 11:18:57 -0800199 for (auto& [id, clientCacheBuffer] : itr->second.second) {
Marissa Wall947d34e2019-03-29 14:03:53 -0700200 client_cache_t cacheId = {processToken, id};
201 for (auto& recipient : clientCacheBuffer.recipients) {
202 sp<ErasedRecipient> erasedRecipient = recipient.promote();
203 if (erasedRecipient) {
204 pendingErase.emplace_back(erasedRecipient, cacheId);
205 }
206 }
207 }
208 mBuffers.erase(itr);
209 }
210
211 for (auto& [recipient, cacheId] : pendingErase) {
212 recipient->bufferErased(cacheId);
213 }
214}
215
216void ClientCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) {
217 ClientCache::getInstance().removeProcess(who);
218}
219
Robert Carrbeba6f02021-02-10 21:06:27 -0800220void ClientCache::dump(std::string& result) {
221 std::lock_guard lock(mMutex);
Dominik Laskowski75788452021-02-09 18:51:25 -0800222 for (const auto& [_, cache] : mBuffers) {
223 base::StringAppendF(&result, " Cache owner: %p\n", cache.first.get());
224
225 for (const auto& [id, entry] : cache.second) {
226 const auto& buffer = entry.buffer->getBuffer();
227 base::StringAppendF(&result, "\tID: %" PRIu64 ", size: %ux%u\n", id, buffer->getWidth(),
228 buffer->getHeight());
Robert Carrbeba6f02021-02-10 21:06:27 -0800229 }
230 }
231}
232
Dominik Laskowski75788452021-02-09 18:51:25 -0800233} // namespace android