• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef USE_M133_SKIA
28 #include "src/core/SkChecksum.h"
29 #endif
30 
31 // after 5 vsync count, destory it
32 #define DELAY_DESTROY_VSYNC_COUNT 5
33 
34 namespace OHOS {
35 namespace Rosen {
36 // modify the RSTypefaceCache instance as global to extend life cycle, fix destructor crash
37 static RSTypefaceCache gRSTypefaceCacheInstance;
38 static const int MAX_CHUNK_SIZE = 20000;
39 
Instance()40 RSTypefaceCache& RSTypefaceCache::Instance()
41 {
42     return gRSTypefaceCacheInstance;
43 }
44 
GenGlobalUniqueId(uint32_t id)45 uint64_t RSTypefaceCache::GenGlobalUniqueId(uint32_t id)
46 {
47     static uint64_t shiftedPid = static_cast<uint64_t>(GetRealPid()) << 32; // 32 for 64-bit unsignd number shift
48     return (shiftedPid | id);
49 }
50 
GetTypefacePid(uint64_t uniqueId)51 pid_t RSTypefaceCache::GetTypefacePid(uint64_t uniqueId)
52 {
53     // 32 for 64-bit unsignd number shift
54     return static_cast<uint32_t>(uniqueId >> 32);
55 }
56 
GetTypefaceId(uint64_t uniqueId)57 uint32_t RSTypefaceCache::GetTypefaceId(uint64_t uniqueId)
58 {
59     return static_cast<uint32_t>(0xFFFFFFFF & uniqueId);
60 }
61 
AddIfFound(uint64_t uniqueId,uint32_t hash)62 bool RSTypefaceCache::AddIfFound(uint64_t uniqueId, uint32_t hash)
63 {
64     std::unordered_map<uint64_t, TypefaceTuple>::iterator iterator = typefaceHashMap_.find(hash);
65     if (iterator != typefaceHashMap_.end()) {
66         typefaceHashCode_[uniqueId] = hash;
67         std::get<1>(iterator->second)++;
68         pid_t pid = GetTypefacePid(uniqueId);
69         if (pid) {
70             MemorySnapshot::Instance().AddCpuMemory(pid, (std::get<0>(iterator->second))->GetSize());
71         }
72         return true;
73     }
74     return false;
75 }
76 
HasTypeface(uint64_t uniqueId,uint32_t hash)77 bool RSTypefaceCache::HasTypeface(uint64_t uniqueId, uint32_t hash)
78 {
79     std::lock_guard<std::mutex> lock(mapMutex_);
80     if (typefaceHashCode_.find(uniqueId) != typefaceHashCode_.end()) {
81         // this client has already registered this typeface
82         return true;
83     }
84 
85     if (hash) {
86         // check if someone else has already registered this typeface, add ref count and
87         // mapping if so.
88         if (AddIfFound(uniqueId, hash)) {
89             return true;
90         }
91 
92         // check if someone else is about to register this typeface -> queue uid
93         std::unordered_map<uint32_t, std::vector<uint64_t>>::iterator iterator = typefaceHashQueue_.find(hash);
94         if (iterator != typefaceHashQueue_.end()) {
95             iterator->second.push_back(uniqueId);
96             return true;
97         } else {
98             typefaceHashQueue_[hash] = { uniqueId };
99         }
100     }
101 
102     return false;
103 }
104 
CacheDrawingTypeface(uint64_t uniqueId,std::shared_ptr<Drawing::Typeface> typeface)105 void RSTypefaceCache::CacheDrawingTypeface(uint64_t uniqueId,
106     std::shared_ptr<Drawing::Typeface> typeface)
107 {
108     if (!(typeface && uniqueId > 0)) {
109         return;
110     }
111 
112     std::lock_guard<std::mutex> lock(mapMutex_);
113     if (typefaceHashCode_.find(uniqueId) != typefaceHashCode_.end()) {
114         return;
115     }
116 
117     uint32_t hash_value = typeface->GetHash();
118     if (!hash_value) { // fallback to slow path if the adapter does not provide hash
119         std::shared_ptr<Drawing::Data> data = typeface->Serialize();
120         if (!data) {
121             return;
122         }
123         const void* stream = data->GetData();
124         size_t size = data->GetSize();
125 #ifdef USE_M133_SKIA
126         hash_value = SkChecksum::Hash32(stream, std::min(size, static_cast<size_t>(MAX_CHUNK_SIZE)));
127 #else
128         hash_value = SkOpts::hash_fn(stream, std::min(size, static_cast<size_t>(MAX_CHUNK_SIZE)), 0);
129 #endif
130     }
131     typefaceHashCode_[uniqueId] = hash_value;
132     pid_t pid = GetTypefacePid(uniqueId);
133     if (typefaceHashMap_.find(hash_value) != typefaceHashMap_.end()) {
134         if (pid) {
135             MemorySnapshot::Instance().AddCpuMemory(pid, typeface->GetSize());
136         }
137         auto [faceCache, ref] = typefaceHashMap_[hash_value];
138         if (faceCache->GetFamilyName() != typeface->GetFamilyName()) {
139             // hash collision
140             typefaceHashCode_[uniqueId] = uniqueId;
141             typefaceHashMap_[uniqueId] = std::make_tuple(typeface, 1);
142             RS_LOGI("CacheDrawingTypeface hash collision");
143         } else {
144             typefaceHashMap_[hash_value] = std::make_tuple(faceCache, ref + 1);
145         }
146         return;
147     }
148     typefaceHashMap_[hash_value] = std::make_tuple(typeface, 1);
149     if (pid) {
150         MemorySnapshot::Instance().AddCpuMemory(pid, typeface->GetSize());
151     }
152     // register queued entries
153     std::unordered_map<uint32_t, std::vector<uint64_t>>::iterator iterator = typefaceHashQueue_.find(hash_value);
154     if (iterator != typefaceHashQueue_.end()) {
155         while (iterator->second.size()) {
156             uint64_t back = iterator->second.back();
157             if (back != uniqueId) {
158                 AddIfFound(back, hash_value);
159             }
160             iterator->second.pop_back();
161         }
162         typefaceHashQueue_.erase(iterator);
163     }
164 }
165 
EmptyAfterErase(std::vector<uint64_t> & vec,size_t ix)166 static bool EmptyAfterErase(std::vector<uint64_t>& vec, size_t ix)
167 {
168     vec.erase(vec.begin() + ix);
169     return vec.empty();
170 }
171 
RemoveHashQueue(std::unordered_map<uint32_t,std::vector<uint64_t>> & typefaceHashQueue,uint64_t globalUniqueId)172 static void RemoveHashQueue(
173     std::unordered_map<uint32_t, std::vector<uint64_t>>& typefaceHashQueue, uint64_t globalUniqueId)
174 {
175     for (auto& ref : typefaceHashQueue) {
176         auto it = std::find(ref.second.begin(), ref.second.end(), globalUniqueId);
177         if (it != ref.second.end()) {
178             size_t ix = std::distance(ref.second.begin(), it);
179             if (EmptyAfterErase(ref.second, ix)) {
180                 typefaceHashQueue.erase(ref.first);
181             }
182             return;
183         }
184     }
185 }
186 
RemoveHashMap(pid_t pid,std::unordered_map<uint64_t,TypefaceTuple> & typefaceHashMap,uint64_t hash_value)187 void RSTypefaceCache::RemoveHashMap(pid_t pid, std::unordered_map<uint64_t, TypefaceTuple>& typefaceHashMap,
188     uint64_t hash_value)
189 {
190     if (typefaceHashMap.find(hash_value) != typefaceHashMap.end()) {
191         auto [typeface, ref] = typefaceHashMap[hash_value];
192         if (pid) {
193             MemorySnapshot::Instance().RemoveCpuMemory(pid, typeface->GetSize());
194         }
195         if (ref <= 1) {
196             typefaceHashMap.erase(hash_value);
197         } else {
198             typefaceHashMap[hash_value] = std::make_tuple(typeface, ref - 1);
199         }
200     }
201 }
202 
RemoveDrawingTypefaceByGlobalUniqueId(uint64_t globalUniqueId)203 void RSTypefaceCache::RemoveDrawingTypefaceByGlobalUniqueId(uint64_t globalUniqueId)
204 {
205     std::lock_guard<std::mutex> lock(mapMutex_);
206     // first check the queue;
207     RemoveHashQueue(typefaceHashQueue_, globalUniqueId);
208 
209     if (typefaceHashCode_.find(globalUniqueId) == typefaceHashCode_.end()) {
210         RS_LOGI("RSTypefaceCache:Failed to find typeface, uniqueid:%{public}u", GetTypefaceId(globalUniqueId));
211         return;
212     }
213     auto hash_value = typefaceHashCode_[globalUniqueId];
214     typefaceHashCode_.erase(globalUniqueId);
215     RS_LOGI("RSTypefaceCache:Remove typeface, uniqueid:%{public}u", GetTypefaceId(globalUniqueId));
216     RemoveHashMap(GetTypefacePid(globalUniqueId), typefaceHashMap_, hash_value);
217 }
218 
GetDrawingTypefaceCache(uint64_t uniqueId) const219 std::shared_ptr<Drawing::Typeface> RSTypefaceCache::GetDrawingTypefaceCache(uint64_t uniqueId) const
220 {
221     if (uniqueId > 0) {
222         std::lock_guard<std::mutex> lock(mapMutex_);
223         if (typefaceHashCode_.find(uniqueId) != typefaceHashCode_.end() &&
224                 typefaceHashMap_.find(typefaceHashCode_.at(uniqueId)) != typefaceHashMap_.end()) {
225             uint32_t hash_value = typefaceHashCode_.at(uniqueId);
226             auto [typeface, ref] = typefaceHashMap_.at(hash_value);
227             return typeface;
228         }
229     }
230     return nullptr;
231 }
232 
PurgeMapWithPid(pid_t pid,std::unordered_map<uint32_t,std::vector<uint64_t>> & map)233 static void PurgeMapWithPid(pid_t pid, std::unordered_map<uint32_t, std::vector<uint64_t>>& map)
234 {
235     // go through queued items;
236     std::vector<size_t> removeList;
237 
238     for (auto& ref : map) {
239         size_t ix { 0 };
240         std::vector<uint64_t> uniqueIdVec = ref.second;
241         for (auto uid : uniqueIdVec) {
242             pid_t pidCache = static_cast<pid_t>(uid >> 32);
243             if (pid != pidCache) {
244                 ix++;
245                 continue;
246             }
247             if (EmptyAfterErase(ref.second, ix)) {
248                 removeList.push_back(ref.first);
249                 break;
250             }
251         }
252     }
253 
254     while (removeList.size()) {
255         map.erase(removeList.back());
256         removeList.pop_back();
257     }
258 }
259 
RemoveDrawingTypefacesByPid(pid_t pid)260 void RSTypefaceCache::RemoveDrawingTypefacesByPid(pid_t pid)
261 {
262     std::lock_guard<std::mutex> lock(mapMutex_);
263     PurgeMapWithPid(pid, typefaceHashQueue_);
264 
265     for (auto it = typefaceHashCode_.begin(); it != typefaceHashCode_.end();) {
266         uint64_t uniqueId = it->first;
267         pid_t pidCache = static_cast<pid_t>(uniqueId >> 32);
268         if (pid == pidCache) {
269             // no need pid, ClearMemoryCache will clear memory snapshot.
270             RemoveHashMap(0, typefaceHashMap_, it->second);
271             it = typefaceHashCode_.erase(it);
272         } else {
273             ++it;
274         }
275     }
276 }
AddDelayDestroyQueue(uint64_t globalUniqueId)277 void RSTypefaceCache::AddDelayDestroyQueue(uint64_t globalUniqueId)
278 {
279     std::lock_guard<std::mutex> lock(listMutex_);
280     delayDestroyTypefaces_.push_back({globalUniqueId, DELAY_DESTROY_VSYNC_COUNT});
281 }
282 
HandleDelayDestroyQueue()283 void RSTypefaceCache::HandleDelayDestroyQueue()
284 {
285     RS_TRACE_FUNC();
286     std::lock_guard<std::mutex> lock(listMutex_);
287     for (auto it = delayDestroyTypefaces_.begin(); it != delayDestroyTypefaces_.end();) {
288         it->refCount--;
289         if (it->refCount == 0) {
290             RemoveDrawingTypefaceByGlobalUniqueId(it->globalUniqueId);
291             it = delayDestroyTypefaces_.erase(it);
292         } else {
293             ++it;
294         }
295     }
296 }
297 
Dump() const298 void RSTypefaceCache::Dump() const
299 {
300     RS_LOGI("RSTypefaceCache Dump : [");
301     RS_LOGI("RSTypefaceCache Dump %{public}s",
302         "---pid typefaceID-------------hash_value------------ref_count-----------familyname--------------");
303     for (auto co : typefaceHashCode_) {
304         if (typefaceHashMap_.find(co.second) != typefaceHashMap_.end()) {
305             auto [typeface, ref] = typefaceHashMap_.at(co.second);
306             RS_LOGI("%{public}s    %{public}s             %{public}s            %{public}s           %{public}s",
307                 "RSTypefaceCache Dump", std::to_string(co.first).c_str(), std::to_string(co.second).c_str(),
308                 std::to_string(ref).c_str(), typeface->GetFamilyName().c_str());
309         }
310     }
311     RS_LOGI("RSTypefaceCache ]");
312 }
313 
ReplaySerialize(std::stringstream & ss)314 void RSTypefaceCache::ReplaySerialize(std::stringstream& ss)
315 {
316     size_t fontCount = 0;
317     ss.write(reinterpret_cast<const char*>(&fontCount), sizeof(fontCount));
318 
319     std::lock_guard<std::mutex> lock(mapMutex_);
320     for (auto co : typefaceHashCode_) {
321         if (typefaceHashMap_.find(co.second) != typefaceHashMap_.end()) {
322             auto [typeface, ref] = typefaceHashMap_.at(co.second);
323 
324             if (auto data = typeface->Serialize()) {
325                 const void* stream = data->GetData();
326                 size_t size = data->GetSize();
327 
328                 ss.write(reinterpret_cast<const char*>(&co.first), sizeof(co.first));
329                 ss.write(reinterpret_cast<const char*>(&size), sizeof(size));
330                 ss.write(reinterpret_cast<const char*>(stream), size);
331                 fontCount++;
332             }
333         }
334     }
335 
336     ss.seekp(0, std::ios_base::beg);
337     ss.write(reinterpret_cast<const char*>(&fontCount), sizeof(fontCount));
338     ss.seekp(0, std::ios_base::end);
339 }
340 
ReplayDeserialize(std::stringstream & ss)341 std::string RSTypefaceCache::ReplayDeserialize(std::stringstream& ss)
342 {
343     constexpr int bitNumber = 30 + 32;
344     uint64_t replayMask = (uint64_t)1 << bitNumber;
345     size_t fontCount;
346     uint64_t uniqueId;
347     size_t dataSize;
348     std::vector<uint8_t> data;
349     constexpr size_t maxTypefaceDataSize = 40'000'000;
350 
351     ss.read(reinterpret_cast<char*>(&fontCount), sizeof(fontCount));
352     for (size_t i = 0; i < fontCount; i++) {
353         ss.read(reinterpret_cast<char*>(&uniqueId), sizeof(uniqueId));
354         ss.read(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
355 
356         if (dataSize > maxTypefaceDataSize) {
357             return "Typeface serialized data is over 40MB";
358         }
359         data.resize(dataSize);
360         ss.read(reinterpret_cast<char*>(data.data()), data.size());
361 
362         if (ss.eof()) {
363             return "Typeface track damaged";
364         }
365 
366         std::shared_ptr<Drawing::Typeface> typeface;
367         typeface = Drawing::Typeface::Deserialize(data.data(), data.size());
368         if (typeface) {
369             uniqueId |= replayMask;
370             CacheDrawingTypeface(uniqueId, typeface);
371         } else {
372             return "Typeface unmarshalling failed";
373         }
374     }
375     return {};
376 }
377 
ReplayClear()378 void RSTypefaceCache::ReplayClear()
379 {
380     std::vector<uint64_t> removeId;
381     constexpr int bitNumber = 30 + 32;
382     uint64_t replayMask = (uint64_t)1 << bitNumber;
383     {
384         std::lock_guard<std::mutex> lock(mapMutex_);
385         for (auto co : typefaceHashCode_) {
386             if (co.first & replayMask) {
387                 removeId.emplace_back(co.first);
388             }
389         }
390     }
391     for (auto uniqueId : removeId) {
392         RemoveDrawingTypefaceByGlobalUniqueId(uniqueId);
393     }
394 }
395 
396 } // namespace Rosen
397 } // namespace OHOS
398