blob: cf932a86c2036173d3adac273385881d8f7f87bc [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>
Vishnu Nairdbbe3852022-01-12 20:22:11 -080025#include <renderengine/impl/ExternalTexture.h>
Dominik Laskowski75788452021-02-09 18:51:25 -080026
Marissa Wall947d34e2019-03-29 14:03:53 -070027#include "ClientCache.h"
28
29namespace android {
30
31ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache);
32
Ady Abrahamd11bade2022-08-01 16:18:03 -070033ClientCache::ClientCache() : mDeathRecipient(sp<CacheDeathRecipient>::make()) {}
Marissa Wall947d34e2019-03-29 14:03:53 -070034
35bool ClientCache::getBuffer(const client_cache_t& cacheId,
36 ClientCacheBuffer** outClientCacheBuffer) {
37 auto& [processToken, id] = cacheId;
38 if (processToken == nullptr) {
39 ALOGE("failed to get buffer, invalid (nullptr) process token");
40 return false;
41 }
42 auto it = mBuffers.find(processToken);
43 if (it == mBuffers.end()) {
44 ALOGE("failed to get buffer, invalid process token");
45 return false;
46 }
47
Valerie Hau90fcc942019-11-18 11:18:57 -080048 auto& processBuffers = it->second.second;
Marissa Wall947d34e2019-03-29 14:03:53 -070049
50 auto bufItr = processBuffers.find(id);
51 if (bufItr == processBuffers.end()) {
Vishnu Nair65eafde2021-03-24 12:17:36 -070052 ALOGV("failed to get buffer, invalid buffer id");
Marissa Wall947d34e2019-03-29 14:03:53 -070053 return false;
54 }
55
56 ClientCacheBuffer& buf = bufItr->second;
57 *outClientCacheBuffer = &buf;
58 return true;
59}
60
Alec Mouri4545a8a2019-08-08 20:05:32 -070061bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
Marissa Wall947d34e2019-03-29 14:03:53 -070062 auto& [processToken, id] = cacheId;
63 if (processToken == nullptr) {
64 ALOGE("failed to cache buffer: invalid process token");
Alec Mouri4545a8a2019-08-08 20:05:32 -070065 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -070066 }
67
68 if (!buffer) {
69 ALOGE("failed to cache buffer: invalid buffer");
Alec Mouri4545a8a2019-08-08 20:05:32 -070070 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -070071 }
72
73 std::lock_guard lock(mMutex);
74 sp<IBinder> token;
75
76 // If this is a new process token, set a death recipient. If the client process dies, we will
77 // get a callback through binderDied.
78 auto it = mBuffers.find(processToken);
79 if (it == mBuffers.end()) {
80 token = processToken.promote();
81 if (!token) {
82 ALOGE("failed to cache buffer: invalid token");
Alec Mouri4545a8a2019-08-08 20:05:32 -070083 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -070084 }
85
chaviw70aa7572021-09-22 12:27:57 -050086 // Only call linkToDeath if not a local binder
87 if (token->localBinder() == nullptr) {
88 status_t err = token->linkToDeath(mDeathRecipient);
89 if (err != NO_ERROR) {
90 ALOGE("failed to cache buffer: could not link to death");
91 return false;
92 }
Marissa Wall947d34e2019-03-29 14:03:53 -070093 }
94 auto [itr, success] =
Valerie Hau90fcc942019-11-18 11:18:57 -080095 mBuffers.emplace(processToken,
96 std::make_pair(token,
97 std::unordered_map<uint64_t, ClientCacheBuffer>()));
Marissa Wall947d34e2019-03-29 14:03:53 -070098 LOG_ALWAYS_FATAL_IF(!success, "failed to insert new process into client cache");
99 it = itr;
100 }
101
Valerie Hau90fcc942019-11-18 11:18:57 -0800102 auto& processBuffers = it->second.second;
Marissa Wall947d34e2019-03-29 14:03:53 -0700103
104 if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
105 ALOGE("failed to cache buffer: cache is full");
Alec Mouri4545a8a2019-08-08 20:05:32 -0700106 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -0700107 }
108
Alec Mouria90a5702021-04-16 16:36:21 +0000109 LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr,
110 "Attempted to build the ClientCache before a RenderEngine instance was "
111 "ready!");
112 processBuffers[id].buffer = std::make_shared<
Vishnu Nairdbbe3852022-01-12 20:22:11 -0800113 renderengine::impl::ExternalTexture>(buffer, *mRenderEngine,
114 renderengine::impl::ExternalTexture::Usage::
115 READABLE);
Alec Mouri4545a8a2019-08-08 20:05:32 -0700116 return true;
Marissa Wall947d34e2019-03-29 14:03:53 -0700117}
118
119void ClientCache::erase(const client_cache_t& cacheId) {
120 auto& [processToken, id] = cacheId;
121 std::vector<sp<ErasedRecipient>> pendingErase;
122 {
123 std::lock_guard lock(mMutex);
124 ClientCacheBuffer* buf = nullptr;
125 if (!getBuffer(cacheId, &buf)) {
126 ALOGE("failed to erase buffer, could not retrieve buffer");
127 return;
128 }
129
130 for (auto& recipient : buf->recipients) {
131 sp<ErasedRecipient> erasedRecipient = recipient.promote();
132 if (erasedRecipient) {
133 pendingErase.push_back(erasedRecipient);
134 }
135 }
136
Valerie Hau90fcc942019-11-18 11:18:57 -0800137 mBuffers[processToken].second.erase(id);
Marissa Wall947d34e2019-03-29 14:03:53 -0700138 }
139
140 for (auto& recipient : pendingErase) {
141 recipient->bufferErased(cacheId);
142 }
143}
144
Alec Mouria90a5702021-04-16 16:36:21 +0000145std::shared_ptr<renderengine::ExternalTexture> ClientCache::get(const client_cache_t& cacheId) {
Marissa Wall947d34e2019-03-29 14:03:53 -0700146 std::lock_guard lock(mMutex);
147
148 ClientCacheBuffer* buf = nullptr;
149 if (!getBuffer(cacheId, &buf)) {
150 ALOGE("failed to get buffer, could not retrieve buffer");
151 return nullptr;
152 }
153
154 return buf->buffer;
155}
156
Alec Mouri4545a8a2019-08-08 20:05:32 -0700157bool ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
Marissa Wall947d34e2019-03-29 14:03:53 -0700158 const wp<ErasedRecipient>& recipient) {
159 std::lock_guard lock(mMutex);
160
161 ClientCacheBuffer* buf = nullptr;
162 if (!getBuffer(cacheId, &buf)) {
Vishnu Nair65eafde2021-03-24 12:17:36 -0700163 ALOGV("failed to register erased recipient, could not retrieve buffer");
Alec Mouri4545a8a2019-08-08 20:05:32 -0700164 return false;
Marissa Wall947d34e2019-03-29 14:03:53 -0700165 }
166 buf->recipients.insert(recipient);
Alec Mouri4545a8a2019-08-08 20:05:32 -0700167 return true;
Marissa Wall947d34e2019-03-29 14:03:53 -0700168}
169
170void ClientCache::unregisterErasedRecipient(const client_cache_t& cacheId,
171 const wp<ErasedRecipient>& recipient) {
172 std::lock_guard lock(mMutex);
173
174 ClientCacheBuffer* buf = nullptr;
175 if (!getBuffer(cacheId, &buf)) {
176 ALOGE("failed to unregister erased recipient");
177 return;
178 }
179
180 buf->recipients.erase(recipient);
181}
182
183void ClientCache::removeProcess(const wp<IBinder>& processToken) {
184 std::vector<std::pair<sp<ErasedRecipient>, client_cache_t>> pendingErase;
185 {
186 if (processToken == nullptr) {
187 ALOGE("failed to remove process, invalid (nullptr) process token");
188 return;
189 }
190 std::lock_guard lock(mMutex);
191 auto itr = mBuffers.find(processToken);
192 if (itr == mBuffers.end()) {
193 ALOGE("failed to remove process, could not find process");
194 return;
195 }
196
Valerie Hau90fcc942019-11-18 11:18:57 -0800197 for (auto& [id, clientCacheBuffer] : itr->second.second) {
Marissa Wall947d34e2019-03-29 14:03:53 -0700198 client_cache_t cacheId = {processToken, id};
199 for (auto& recipient : clientCacheBuffer.recipients) {
200 sp<ErasedRecipient> erasedRecipient = recipient.promote();
201 if (erasedRecipient) {
202 pendingErase.emplace_back(erasedRecipient, cacheId);
203 }
204 }
205 }
206 mBuffers.erase(itr);
207 }
208
209 for (auto& [recipient, cacheId] : pendingErase) {
210 recipient->bufferErased(cacheId);
211 }
212}
213
214void ClientCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) {
215 ClientCache::getInstance().removeProcess(who);
216}
217
Robert Carrbeba6f02021-02-10 21:06:27 -0800218void ClientCache::dump(std::string& result) {
219 std::lock_guard lock(mMutex);
Dominik Laskowski75788452021-02-09 18:51:25 -0800220 for (const auto& [_, cache] : mBuffers) {
221 base::StringAppendF(&result, " Cache owner: %p\n", cache.first.get());
222
223 for (const auto& [id, entry] : cache.second) {
224 const auto& buffer = entry.buffer->getBuffer();
225 base::StringAppendF(&result, "\tID: %" PRIu64 ", size: %ux%u\n", id, buffer->getWidth(),
226 buffer->getHeight());
Robert Carrbeba6f02021-02-10 21:06:27 -0800227 }
228 }
229}
230
Dominik Laskowski75788452021-02-09 18:51:25 -0800231} // namespace android