1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <iterator>
17 #include <unistd.h>
18 #include "memory/rs_memory_snapshot.h"
19 #include "render/rs_typeface_cache.h"
20 #include "sandbox_utils.h"
21 #include "src/core/SkLRUCache.h"
22 #include "platform/common/rs_log.h"
23 #include "rs_trace.h"
24 #include <sstream>
25 #include <algorithm>
26
27 // after 5 vsync count, destory it
28 #define DELAY_DESTROY_VSYNC_COUNT 5
29
30 namespace OHOS {
31 namespace Rosen {
32 // modify the RSTypefaceCache instance as global to extend life cycle, fix destructor crash
33 static RSTypefaceCache gRSTypefaceCacheInstance;
34 static const int MAX_CHUNK_SIZE = 20000;
35
Instance()36 RSTypefaceCache& RSTypefaceCache::Instance()
37 {
38 return gRSTypefaceCacheInstance;
39 }
40
GenGlobalUniqueId(uint32_t id)41 uint64_t RSTypefaceCache::GenGlobalUniqueId(uint32_t id)
42 {
43 static uint64_t shiftedPid = static_cast<uint64_t>(GetRealPid()) << 32; // 32 for 64-bit unsignd number shift
44 return (shiftedPid | id);
45 }
46
GetTypefacePid(uint64_t uniqueId)47 pid_t RSTypefaceCache::GetTypefacePid(uint64_t uniqueId)
48 {
49 // 32 for 64-bit unsignd number shift
50 return static_cast<uint32_t>(uniqueId >> 32);
51 }
52
GetTypefaceId(uint64_t uniqueId)53 uint32_t RSTypefaceCache::GetTypefaceId(uint64_t uniqueId)
54 {
55 return static_cast<uint32_t>(0xFFFFFFFF & uniqueId);
56 }
57
AddIfFound(uint64_t uniqueId,uint32_t hash)58 bool RSTypefaceCache::AddIfFound(uint64_t uniqueId, uint32_t hash)
59 {
60 std::unordered_map<uint64_t, TypefaceTuple>::iterator iterator = typefaceHashMap_.find(hash);
61 if (iterator != typefaceHashMap_.end()) {
62 typefaceHashCode_[uniqueId] = hash;
63 std::get<1>(iterator->second)++;
64 pid_t pid = GetTypefacePid(uniqueId);
65 if (pid) {
66 MemorySnapshot::Instance().AddCpuMemory(pid, (std::get<0>(iterator->second))->GetSize());
67 }
68 return true;
69 }
70 return false;
71 }
72
HasTypeface(uint64_t uniqueId,uint32_t hash)73 bool RSTypefaceCache::HasTypeface(uint64_t uniqueId, uint32_t hash)
74 {
75 std::lock_guard<std::mutex> lock(mapMutex_);
76 if (typefaceHashCode_.find(uniqueId) != typefaceHashCode_.end()) {
77 // this client has already registered this typeface
78 return true;
79 }
80
81 if (hash) {
82 // check if someone else has already registered this typeface, add ref count and
83 // mapping if so.
84 if (AddIfFound(uniqueId, hash)) {
85 return true;
86 }
87
88 // check if someone else is about to register this typeface -> queue uid
89 std::unordered_map<uint32_t, std::vector<uint64_t>>::iterator iterator = typefaceHashQueue_.find(hash);
90 if (iterator != typefaceHashQueue_.end()) {
91 iterator->second.push_back(uniqueId);
92 return true;
93 } else {
94 typefaceHashQueue_[hash] = { uniqueId };
95 }
96 }
97
98 return false;
99 }
100
CacheDrawingTypeface(uint64_t uniqueId,std::shared_ptr<Drawing::Typeface> typeface)101 void RSTypefaceCache::CacheDrawingTypeface(uint64_t uniqueId,
102 std::shared_ptr<Drawing::Typeface> typeface)
103 {
104 if (!(typeface && uniqueId > 0)) {
105 return;
106 }
107
108 std::lock_guard<std::mutex> lock(mapMutex_);
109 if (typefaceHashCode_.find(uniqueId) != typefaceHashCode_.end()) {
110 return;
111 }
112
113 uint32_t hash_value = typeface->GetHash();
114 if (!hash_value) { // fallback to slow path if the adapter does not provide hash
115 std::shared_ptr<Drawing::Data> data = typeface->Serialize();
116 const void* stream = data->GetData();
117 size_t size = data->GetSize();
118 hash_value = SkOpts::hash_fn(stream, std::min(size, static_cast<size_t>(MAX_CHUNK_SIZE)), 0);
119 }
120 typefaceHashCode_[uniqueId] = hash_value;
121 pid_t pid = GetTypefacePid(uniqueId);
122 if (typefaceHashMap_.find(hash_value) != typefaceHashMap_.end()) {
123 if (pid) {
124 MemorySnapshot::Instance().AddCpuMemory(pid, typeface->GetSize());
125 }
126 auto [faceCache, ref] = typefaceHashMap_[hash_value];
127 if (faceCache->GetFamilyName() != typeface->GetFamilyName()) {
128 // hash collision
129 typefaceHashCode_[uniqueId] = uniqueId;
130 typefaceHashMap_[uniqueId] = std::make_tuple(typeface, 1);
131 RS_LOGI("CacheDrawingTypeface hash collision");
132 } else {
133 typefaceHashMap_[hash_value] = std::make_tuple(faceCache, ref + 1);
134 }
135 return;
136 }
137 typefaceHashMap_[hash_value] = std::make_tuple(typeface, 1);
138 if (pid) {
139 MemorySnapshot::Instance().AddCpuMemory(pid, typeface->GetSize());
140 }
141 // register queued entries
142 std::unordered_map<uint32_t, std::vector<uint64_t>>::iterator iterator = typefaceHashQueue_.find(hash_value);
143 if (iterator != typefaceHashQueue_.end()) {
144 while (iterator->second.size()) {
145 uint64_t back = iterator->second.back();
146 if (back != uniqueId) {
147 AddIfFound(back, hash_value);
148 }
149 iterator->second.pop_back();
150 }
151 typefaceHashQueue_.erase(iterator);
152 }
153 }
154
EmptyAfterErase(std::vector<uint64_t> & vec,size_t ix)155 static bool EmptyAfterErase(std::vector<uint64_t>& vec, size_t ix)
156 {
157 vec.erase(vec.begin() + ix);
158 return vec.empty();
159 }
160
RemoveHashQueue(std::unordered_map<uint32_t,std::vector<uint64_t>> & typefaceHashQueue,uint64_t globalUniqueId)161 static void RemoveHashQueue(
162 std::unordered_map<uint32_t, std::vector<uint64_t>>& typefaceHashQueue, uint64_t globalUniqueId)
163 {
164 for (auto& ref : typefaceHashQueue) {
165 auto it = std::find(ref.second.begin(), ref.second.end(), globalUniqueId);
166 if (it != ref.second.end()) {
167 size_t ix = std::distance(ref.second.begin(), it);
168 if (EmptyAfterErase(ref.second, ix)) {
169 typefaceHashQueue.erase(ref.first);
170 }
171 return;
172 }
173 }
174 }
175
RemoveHashMap(pid_t pid,std::unordered_map<uint64_t,TypefaceTuple> & typefaceHashMap,uint64_t hash_value)176 void RSTypefaceCache::RemoveHashMap(pid_t pid, std::unordered_map<uint64_t, TypefaceTuple>& typefaceHashMap,
177 uint64_t hash_value)
178 {
179 if (typefaceHashMap.find(hash_value) != typefaceHashMap.end()) {
180 auto [typeface, ref] = typefaceHashMap[hash_value];
181 if (pid) {
182 MemorySnapshot::Instance().RemoveCpuMemory(pid, typeface->GetSize());
183 }
184 if (ref <= 1) {
185 typefaceHashMap.erase(hash_value);
186 } else {
187 typefaceHashMap[hash_value] = std::make_tuple(typeface, ref - 1);
188 }
189 }
190 }
191
RemoveDrawingTypefaceByGlobalUniqueId(uint64_t globalUniqueId)192 void RSTypefaceCache::RemoveDrawingTypefaceByGlobalUniqueId(uint64_t globalUniqueId)
193 {
194 std::lock_guard<std::mutex> lock(mapMutex_);
195 // first check the queue;
196 RemoveHashQueue(typefaceHashQueue_, globalUniqueId);
197
198 if (typefaceHashCode_.find(globalUniqueId) == typefaceHashCode_.end()) {
199 return;
200 }
201 auto hash_value = typefaceHashCode_[globalUniqueId];
202 typefaceHashCode_.erase(globalUniqueId);
203
204 RemoveHashMap(GetTypefacePid(globalUniqueId), typefaceHashMap_, hash_value);
205 }
206
GetDrawingTypefaceCache(uint64_t uniqueId) const207 std::shared_ptr<Drawing::Typeface> RSTypefaceCache::GetDrawingTypefaceCache(uint64_t uniqueId) const
208 {
209 if (uniqueId > 0) {
210 std::lock_guard<std::mutex> lock(mapMutex_);
211 if (typefaceHashCode_.find(uniqueId) != typefaceHashCode_.end() &&
212 typefaceHashMap_.find(typefaceHashCode_.at(uniqueId)) != typefaceHashMap_.end()) {
213 uint32_t hash_value = typefaceHashCode_.at(uniqueId);
214 auto [typeface, ref] = typefaceHashMap_.at(hash_value);
215 return typeface;
216 }
217 }
218 return nullptr;
219 }
220
PurgeMapWithPid(pid_t pid,std::unordered_map<uint32_t,std::vector<uint64_t>> & map)221 static void PurgeMapWithPid(pid_t pid, std::unordered_map<uint32_t, std::vector<uint64_t>>& map)
222 {
223 // go through queued items;
224 std::vector<size_t> removeList;
225
226 for (auto& ref : map) {
227 size_t ix { 0 };
228 std::vector<uint64_t> uniqueIdVec = ref.second;
229 for (auto uid : uniqueIdVec) {
230 pid_t pidCache = static_cast<pid_t>(uid >> 32);
231 if (pid != pidCache) {
232 ix++;
233 continue;
234 }
235 if (EmptyAfterErase(ref.second, ix)) {
236 removeList.push_back(ref.first);
237 break;
238 }
239 }
240 }
241
242 while (removeList.size()) {
243 map.erase(removeList.back());
244 removeList.pop_back();
245 }
246 }
247
RemoveDrawingTypefacesByPid(pid_t pid)248 void RSTypefaceCache::RemoveDrawingTypefacesByPid(pid_t pid)
249 {
250 std::lock_guard<std::mutex> lock(mapMutex_);
251 PurgeMapWithPid(pid, typefaceHashQueue_);
252
253 for (auto it = typefaceHashCode_.begin(); it != typefaceHashCode_.end();) {
254 uint64_t uniqueId = it->first;
255 pid_t pidCache = static_cast<pid_t>(uniqueId >> 32);
256 if (pid == pidCache) {
257 // no need pid, ClearMemoryCache will clear memory snapshot.
258 RemoveHashMap(0, typefaceHashMap_, it->second);
259 it = typefaceHashCode_.erase(it);
260 } else {
261 ++it;
262 }
263 }
264 }
AddDelayDestroyQueue(uint64_t globalUniqueId)265 void RSTypefaceCache::AddDelayDestroyQueue(uint64_t globalUniqueId)
266 {
267 std::lock_guard<std::mutex> lock(listMutex_);
268 delayDestroyTypefaces_.push_back({globalUniqueId, DELAY_DESTROY_VSYNC_COUNT});
269 }
270
HandleDelayDestroyQueue()271 void RSTypefaceCache::HandleDelayDestroyQueue()
272 {
273 RS_TRACE_FUNC();
274 std::lock_guard<std::mutex> lock(listMutex_);
275 for (auto it = delayDestroyTypefaces_.begin(); it != delayDestroyTypefaces_.end();) {
276 it->refCount--;
277 if (it->refCount == 0) {
278 RemoveDrawingTypefaceByGlobalUniqueId(it->globalUniqueId);
279 it = delayDestroyTypefaces_.erase(it);
280 } else {
281 ++it;
282 }
283 }
284 }
285
Dump() const286 void RSTypefaceCache::Dump() const
287 {
288 RS_LOGI("RSTypefaceCache Dump : [");
289 RS_LOGI("RSTypefaceCache Dump %{public}s",
290 "---pid typefaceID-------------hash_value------------ref_count-----------familyname--------------");
291 for (auto co : typefaceHashCode_) {
292 if (typefaceHashMap_.find(co.second) != typefaceHashMap_.end()) {
293 auto [typeface, ref] = typefaceHashMap_.at(co.second);
294 RS_LOGI("%{public}s %{public}s %{public}s %{public}s %{public}s",
295 "RSTypefaceCache Dump", std::to_string(co.first).c_str(), std::to_string(co.second).c_str(),
296 std::to_string(ref).c_str(), typeface->GetFamilyName().c_str());
297 }
298 }
299 RS_LOGI("RSTypefaceCache ]");
300 }
301
ReplaySerialize(std::stringstream & ss)302 void RSTypefaceCache::ReplaySerialize(std::stringstream& ss)
303 {
304 size_t fontCount = 0;
305 ss.write(reinterpret_cast<const char*>(&fontCount), sizeof(fontCount));
306
307 for (auto co : typefaceHashCode_) {
308 if (typefaceHashMap_.find(co.second) != typefaceHashMap_.end()) {
309 auto [typeface, ref] = typefaceHashMap_.at(co.second);
310
311 if (auto data = typeface->Serialize()) {
312 const void* stream = data->GetData();
313 size_t size = data->GetSize();
314
315 ss.write(reinterpret_cast<const char*>(&co.first), sizeof(co.first));
316 ss.write(reinterpret_cast<const char*>(&size), sizeof(size));
317 ss.write(reinterpret_cast<const char*>(stream), size);
318 fontCount++;
319 }
320 }
321 }
322
323 ss.seekp(0, std::ios_base::beg);
324 ss.write(reinterpret_cast<const char*>(&fontCount), sizeof(fontCount));
325 ss.seekp(0, std::ios_base::end);
326 }
327
ReplayDeserialize(std::stringstream & ss)328 void RSTypefaceCache::ReplayDeserialize(std::stringstream& ss)
329 {
330 constexpr int bitNumber = 30 + 32;
331 uint64_t replayMask = (uint64_t)1 << bitNumber;
332 size_t fontCount;
333 uint64_t uniqueId;
334 size_t dataSize;
335 std::vector<uint8_t> data;
336
337 ss.read(reinterpret_cast<char*>(&fontCount), sizeof(fontCount));
338 for (size_t i = 0; i < fontCount; i++) {
339 ss.read(reinterpret_cast<char*>(&uniqueId), sizeof(uniqueId));
340 ss.read(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
341
342 // Check if the stream is not empty and data size is not too large (2 MiB).
343 constexpr size_t maxDataSize = 2 * 1024 * 1024;
344 if (ss.eof() || (dataSize > maxDataSize)) {
345 break;
346 }
347 data.resize(dataSize);
348 ss.read(reinterpret_cast<char*>(data.data()), dataSize);
349
350 std::shared_ptr<Drawing::Typeface> typeface;
351 typeface = Drawing::Typeface::Deserialize(data.data(), dataSize);
352 if (typeface) {
353 uniqueId |= replayMask;
354 CacheDrawingTypeface(uniqueId, typeface);
355 }
356 }
357 }
358
ReplayClear()359 void RSTypefaceCache::ReplayClear()
360 {
361 std::vector<uint64_t> removeId;
362 constexpr int bitNumber = 30 + 32;
363 uint64_t replayMask = (uint64_t)1 << bitNumber;
364 for (auto co : typefaceHashCode_) {
365 if (co.first & replayMask) {
366 removeId.emplace_back(co.first);
367 }
368 }
369 for (auto uniqueId : removeId) {
370 RemoveDrawingTypefaceByGlobalUniqueId(uniqueId);
371 }
372 }
373
374 } // namespace Rosen
375 } // namespace OHOS
376