blob: e7b89957036319e98ac23dc2b1c7cd6522a2121c [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>
25
Marissa Wall947d34e2019-03-29 14:03:53 -070026#include "ClientCache.h"
27
28namespace android {
29
30ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache);
31
32ClientCache::ClientCache() : mDeathRecipient(new CacheDeathRecipient) {}
33
34bool ClientCache::getBuffer(const client_cache_t& cacheId,
35 ClientCacheBuffer** outClientCacheBuffer) {
36 auto& [processToken, id] = cacheId;
37 if (processToken == nullptr) {
38 ALOGE("failed to get buffer, invalid (nullptr) process token");
39 return false;
40 }
41 auto it = mBuffers.find(processToken);
42 if (it == mBuffers.end()) {
43 ALOGE("failed to get buffer, invalid process token");
44 return false;
45 }
46
Valerie Hau90fcc942019-11-18 11:18:57 -080047 auto& processBuffers = it->second.second;
Marissa Wall947d34e2019-03-29 14:03:53 -070048
49 auto bufItr = processBuffers.find(id);
50 if (bufItr == processBuffers.end()) {
Vishnu Nair65eafde2021-03-24 12:17:36 -070051 ALOGV("failed to get buffer, invalid buffer id");
Marissa Wall947d34e2019-03-29 14:03:53 -070052 return false;
53 }
54
55 ClientCacheBuffer& buf = bufItr->second;
56 *outClientCacheBuffer = &buf;
57 return true;
58}
59
Alec Mouri4545a8a2019-08-08 20:05:32 -070060bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
Marissa Wall947d34e2019-03-29 14:03:53 -070061 auto& [processToken, id] = cacheId;
62 if (processToken == nullptr) {
63 ALOGE("failed to cache buffer: invalid process token");
Alec Mouri4545a8a2019-08-08 20:05:32 -070064 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -070065 }
66
67 if (!buffer) {
68 ALOGE("failed to cache buffer: invalid buffer");
Alec Mouri4545a8a2019-08-08 20:05:32 -070069 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -070070 }
71
72 std::lock_guard lock(mMutex);
73 sp<IBinder> token;
74
75 // If this is a new process token, set a death recipient. If the client process dies, we will
76 // get a callback through binderDied.
77 auto it = mBuffers.find(processToken);
78 if (it == mBuffers.end()) {
79 token = processToken.promote();
80 if (!token) {
81 ALOGE("failed to cache buffer: invalid token");
Alec Mouri4545a8a2019-08-08 20:05:32 -070082 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -070083 }
84
chaviw70aa7572021-09-22 12:27:57 -050085 // Only call linkToDeath if not a local binder
86 if (token->localBinder() == nullptr) {
87 status_t err = token->linkToDeath(mDeathRecipient);
88 if (err != NO_ERROR) {
89 ALOGE("failed to cache buffer: could not link to death");
90 return false;
91 }
Marissa Wall947d34e2019-03-29 14:03:53 -070092 }
93 auto [itr, success] =
Valerie Hau90fcc942019-11-18 11:18:57 -080094 mBuffers.emplace(processToken,
95 std::make_pair(token,
96 std::unordered_map<uint64_t, ClientCacheBuffer>()));
Marissa Wall947d34e2019-03-29 14:03:53 -070097 LOG_ALWAYS_FATAL_IF(!success, "failed to insert new process into client cache");
98 it = itr;
99 }
100
Valerie Hau90fcc942019-11-18 11:18:57 -0800101 auto& processBuffers = it->second.second;
Marissa Wall947d34e2019-03-29 14:03:53 -0700102
103 if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
104 ALOGE("failed to cache buffer: cache is full");
Alec Mouri4545a8a2019-08-08 20:05:32 -0700105 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -0700106 }
107
Alec Mouria90a5702021-04-16 16:36:21 +0000108 LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr,
109 "Attempted to build the ClientCache before a RenderEngine instance was "
110 "ready!");
111 processBuffers[id].buffer = std::make_shared<
112 renderengine::ExternalTexture>(buffer, *mRenderEngine,
113 renderengine::ExternalTexture::Usage::READABLE);
Alec Mouri4545a8a2019-08-08 20:05:32 -0700114 return true;
Marissa Wall947d34e2019-03-29 14:03:53 -0700115}
116
117void ClientCache::erase(const client_cache_t& cacheId) {
118 auto& [processToken, id] = cacheId;
119 std::vector<sp<ErasedRecipient>> pendingErase;
120 {
121 std::lock_guard lock(mMutex);
122 ClientCacheBuffer* buf = nullptr;
123 if (!getBuffer(cacheId, &buf)) {
124 ALOGE("failed to erase buffer, could not retrieve buffer");
125 return;
126 }
127
128 for (auto& recipient : buf->recipients) {
129 sp<ErasedRecipient> erasedRecipient = recipient.promote();
130 if (erasedRecipient) {
131 pendingErase.push_back(erasedRecipient);
132 }
133 }
134
Valerie Hau90fcc942019-11-18 11:18:57 -0800135 mBuffers[processToken].second.erase(id);
Marissa Wall947d34e2019-03-29 14:03:53 -0700136 }
137
138 for (auto& recipient : pendingErase) {
139 recipient->bufferErased(cacheId);
140 }
141}
142
Alec Mouria90a5702021-04-16 16:36:21 +0000143std::shared_ptr<renderengine::ExternalTexture> ClientCache::get(const client_cache_t& cacheId) {
Marissa Wall947d34e2019-03-29 14:03:53 -0700144 std::lock_guard lock(mMutex);
145
146 ClientCacheBuffer* buf = nullptr;
147 if (!getBuffer(cacheId, &buf)) {
148 ALOGE("failed to get buffer, could not retrieve buffer");
149 return nullptr;
150 }
151
152 return buf->buffer;
153}
154
Alec Mouri4545a8a2019-08-08 20:05:32 -0700155bool ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
Marissa Wall947d34e2019-03-29 14:03:53 -0700156 const wp<ErasedRecipient>& recipient) {
157 std::lock_guard lock(mMutex);
158
159 ClientCacheBuffer* buf = nullptr;
160 if (!getBuffer(cacheId, &buf)) {
Vishnu Nair65eafde2021-03-24 12:17:36 -0700161 ALOGV("failed to register erased recipient, could not retrieve buffer");
Alec Mouri4545a8a2019-08-08 20:05:32 -0700162 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -0700163 }
164 buf->recipients.insert(recipient);
Alec Mouri4545a8a2019-08-08 20:05:32 -0700165 return true;
Marissa Wall947d34e2019-03-29 14:03:53 -0700166}
167
168void ClientCache::unregisterErasedRecipient(const client_cache_t& cacheId,
169 const wp<ErasedRecipient>& recipient) {
170 std::lock_guard lock(mMutex);
171
172 ClientCacheBuffer* buf = nullptr;
173 if (!getBuffer(cacheId, &buf)) {
174 ALOGE("failed to unregister erased recipient");
175 return;
176 }
177
178 buf->recipients.erase(recipient);
179}
180
181void ClientCache::removeProcess(const wp<IBinder>& processToken) {
182 std::vector<std::pair<sp<ErasedRecipient>, client_cache_t>> pendingErase;
183 {
184 if (processToken == nullptr) {
185 ALOGE("failed to remove process, invalid (nullptr) process token");
186 return;
187 }
188 std::lock_guard lock(mMutex);
189 auto itr = mBuffers.find(processToken);
190 if (itr == mBuffers.end()) {
191 ALOGE("failed to remove process, could not find process");
192 return;
193 }
194
Valerie Hau90fcc942019-11-18 11:18:57 -0800195 for (auto& [id, clientCacheBuffer] : itr->second.second) {
Marissa Wall947d34e2019-03-29 14:03:53 -0700196 client_cache_t cacheId = {processToken, id};
197 for (auto& recipient : clientCacheBuffer.recipients) {
198 sp<ErasedRecipient> erasedRecipient = recipient.promote();
199 if (erasedRecipient) {
200 pendingErase.emplace_back(erasedRecipient, cacheId);
201 }
202 }
203 }
204 mBuffers.erase(itr);
205 }
206
207 for (auto& [recipient, cacheId] : pendingErase) {
208 recipient->bufferErased(cacheId);
209 }
210}
211
212void ClientCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) {
213 ClientCache::getInstance().removeProcess(who);
214}
215
Robert Carrbeba6f02021-02-10 21:06:27 -0800216void ClientCache::dump(std::string& result) {
217 std::lock_guard lock(mMutex);
Dominik Laskowski75788452021-02-09 18:51:25 -0800218 for (const auto& [_, cache] : mBuffers) {
219 base::StringAppendF(&result, " Cache owner: %p\n", cache.first.get());
220
221 for (const auto& [id, entry] : cache.second) {
222 const auto& buffer = entry.buffer->getBuffer();
223 base::StringAppendF(&result, "\tID: %" PRIu64 ", size: %ux%u\n", id, buffer->getWidth(),
224 buffer->getHeight());
Robert Carrbeba6f02021-02-10 21:06:27 -0800225 }
226 }
227}
228
Dominik Laskowski75788452021-02-09 18:51:25 -0800229} // namespace android