• 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 // 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         if (!data) {
117             return;
118         }
119         const void* stream = data->GetData();
120         size_t size = data->GetSize();
121         hash_value = SkOpts::hash_fn(stream, std::min(size, static_cast<size_t>(MAX_CHUNK_SIZE)), 0);
122     }
123     typefaceHashCode_[uniqueId] = hash_value;
124     pid_t pid = GetTypefacePid(uniqueId);
125     if (typefaceHashMap_.find(hash_value) != typefaceHashMap_.end()) {
126         if (pid) {
127             MemorySnapshot::Instance().AddCpuMemory(pid, typeface->GetSize());
128         }
129         auto [faceCache, ref] = typefaceHashMap_[hash_value];
130         if (faceCache->GetFamilyName() != typeface->GetFamilyName()) {
131             // hash collision
132             typefaceHashCode_[uniqueId] = uniqueId;
133             typefaceHashMap_[uniqueId] = std::make_tuple(typeface, 1);
134             RS_LOGI("CacheDrawingTypeface hash collision");
135         } else {
136             typefaceHashMap_[hash_value] = std::make_tuple(faceCache, ref + 1);
137         }
138         return;
139     }
140     typefaceHashMap_[hash_value] = std::make_tuple(typeface, 1);
141     if (pid) {
142         MemorySnapshot::Instance().AddCpuMemory(pid, typeface->GetSize());
143     }
144     // register queued entries
145     std::unordered_map<uint32_t, std::vector<uint64_t>>::iterator iterator = typefaceHashQueue_.find(hash_value);
146     if (iterator != typefaceHashQueue_.end()) {
147         while (iterator->second.size()) {
148             uint64_t back = iterator->second.back();
149             if (back != uniqueId) {
150                 AddIfFound(back, hash_value);
151             }
152             iterator->second.pop_back();
153         }
154         typefaceHashQueue_.erase(iterator);
155     }
156 }
157 
EmptyAfterErase(std::vector<uint64_t> & vec,size_t ix)158 static bool EmptyAfterErase(std::vector<uint64_t>& vec, size_t ix)
159 {
160     vec.erase(vec.begin() + ix);
161     return vec.empty();
162 }
163 
RemoveHashQueue(std::unordered_map<uint32_t,std::vector<uint64_t>> & typefaceHashQueue,uint64_t globalUniqueId)164 static void RemoveHashQueue(
165     std::unordered_map<uint32_t, std::vector<uint64_t>>& typefaceHashQueue, uint64_t globalUniqueId)
166 {
167     for (auto& ref : typefaceHashQueue) {
168         auto it = std::find(ref.second.begin(), ref.second.end(), globalUniqueId);
169         if (it != ref.second.end()) {
170             size_t ix = std::distance(ref.second.begin(), it);
171             if (EmptyAfterErase(ref.second, ix)) {
172                 typefaceHashQueue.erase(ref.first);
173             }
174             return;
175         }
176     }
177 }
178 
RemoveHashMap(pid_t pid,std::unordered_map<uint64_t,TypefaceTuple> & typefaceHashMap,uint64_t hash_value)179 void RSTypefaceCache::RemoveHashMap(pid_t pid, std::unordered_map<uint64_t, TypefaceTuple>& typefaceHashMap,
180     uint64_t hash_value)
181 {
182     if (typefaceHashMap.find(hash_value) != typefaceHashMap.end()) {
183         auto [typeface, ref] = typefaceHashMap[hash_value];
184         if (pid) {
185             MemorySnapshot::Instance().RemoveCpuMemory(pid, typeface->GetSize());
186         }
187         if (ref <= 1) {
188             typefaceHashMap.erase(hash_value);
189         } else {
190             typefaceHashMap[hash_value] = std::make_tuple(typeface, ref - 1);
191         }
192     }
193 }
194 
RemoveDrawingTypefaceByGlobalUniqueId(uint64_t globalUniqueId)195 void RSTypefaceCache::RemoveDrawingTypefaceByGlobalUniqueId(uint64_t globalUniqueId)
196 {
197     std::lock_guard<std::mutex> lock(mapMutex_);
198     // first check the queue;
199     RemoveHashQueue(typefaceHashQueue_, globalUniqueId);
200 
201     if (typefaceHashCode_.find(globalUniqueId) == typefaceHashCode_.end()) {
202         RS_LOGI("RSTypefaceCache:Failed to find typeface, uniqueid:%{public}u", GetTypefaceId(globalUniqueId));
203         return;
204     }
205     auto hash_value = typefaceHashCode_[globalUniqueId];
206     typefaceHashCode_.erase(globalUniqueId);
207     RS_LOGI("RSTypefaceCache:Remove typeface, uniqueid:%{public}u", GetTypefaceId(globalUniqueId));
208     RemoveHashMap(GetTypefacePid(globalUniqueId), typefaceHashMap_, hash_value);
209 }
210 
GetDrawingTypefaceCache(uint64_t uniqueId) const211 std::shared_ptr<Drawing::Typeface> RSTypefaceCache::GetDrawingTypefaceCache(uint64_t uniqueId) const
212 {
213     if (uniqueId > 0) {
214         std::lock_guard<std::mutex> lock(mapMutex_);
215         if (typefaceHashCode_.find(uniqueId) != typefaceHashCode_.end() &&
216                 typefaceHashMap_.find(typefaceHashCode_.at(uniqueId)) != typefaceHashMap_.end()) {
217             uint32_t hash_value = typefaceHashCode_.at(uniqueId);
218             auto [typeface, ref] = typefaceHashMap_.at(hash_value);
219             return typeface;
220         }
221     }
222     return nullptr;
223 }
224 
PurgeMapWithPid(pid_t pid,std::unordered_map<uint32_t,std::vector<uint64_t>> & map)225 static void PurgeMapWithPid(pid_t pid, std::unordered_map<uint32_t, std::vector<uint64_t>>& map)
226 {
227     // go through queued items;
228     std::vector<size_t> removeList;
229 
230     for (auto& ref : map) {
231         size_t ix { 0 };
232         std::vector<uint64_t> uniqueIdVec = ref.second;
233         for (auto uid : uniqueIdVec) {
234             pid_t pidCache = static_cast<pid_t>(uid >> 32);
235             if (pid != pidCache) {
236                 ix++;
237                 continue;
238             }
239             if (EmptyAfterErase(ref.second, ix)) {
240                 removeList.push_back(ref.first);
241                 break;
242             }
243         }
244     }
245 
246     while (removeList.size()) {
247         map.erase(removeList.back());
248         removeList.pop_back();
249     }
250 }
251 
RemoveDrawingTypefacesByPid(pid_t pid)252 void RSTypefaceCache::RemoveDrawingTypefacesByPid(pid_t pid)
253 {
254     std::lock_guard<std::mutex> lock(mapMutex_);
255     PurgeMapWithPid(pid, typefaceHashQueue_);
256 
257     for (auto it = typefaceHashCode_.begin(); it != typefaceHashCode_.end();) {
258         uint64_t uniqueId = it->first;
259         pid_t pidCache = static_cast<pid_t>(uniqueId >> 32);
260         if (pid == pidCache) {
261             // no need pid, ClearMemoryCache will clear memory snapshot.
262             RemoveHashMap(0, typefaceHashMap_, it->second);
263             it = typefaceHashCode_.erase(it);
264         } else {
265             ++it;
266         }
267     }
268 }
AddDelayDestroyQueue(uint64_t globalUniqueId)269 void RSTypefaceCache::AddDelayDestroyQueue(uint64_t globalUniqueId)
270 {
271     std::lock_guard<std::mutex> lock(listMutex_);
272     delayDestroyTypefaces_.push_back({globalUniqueId, DELAY_DESTROY_VSYNC_COUNT});
273 }
274 
HandleDelayDestroyQueue()275 void RSTypefaceCache::HandleDelayDestroyQueue()
276 {
277     RS_TRACE_FUNC();
278     std::lock_guard<std::mutex> lock(listMutex_);
279     for (auto it = delayDestroyTypefaces_.begin(); it != delayDestroyTypefaces_.end();) {
280         it->refCount--;
281         if (it->refCount == 0) {
282             RemoveDrawingTypefaceByGlobalUniqueId(it->globalUniqueId);
283             it = delayDestroyTypefaces_.erase(it);
284         } else {
285             ++it;
286         }
287     }
288 }
289 
Dump() const290 void RSTypefaceCache::Dump() const
291 {
292     RS_LOGI("RSTypefaceCache Dump : [");
293     RS_LOGI("RSTypefaceCache Dump %{public}s",
294         "---pid typefaceID-------------hash_value------------ref_count-----------familyname--------------");
295     for (auto co : typefaceHashCode_) {
296         if (typefaceHashMap_.find(co.second) != typefaceHashMap_.end()) {
297             auto [typeface, ref] = typefaceHashMap_.at(co.second);
298             RS_LOGI("%{public}s    %{public}s             %{public}s            %{public}s           %{public}s",
299                 "RSTypefaceCache Dump", std::to_string(co.first).c_str(), std::to_string(co.second).c_str(),
300                 std::to_string(ref).c_str(), typeface->GetFamilyName().c_str());
301         }
302     }
303     RS_LOGI("RSTypefaceCache ]");
304 }
305 
ReplaySerialize(std::stringstream & ss)306 void RSTypefaceCache::ReplaySerialize(std::stringstream& ss)
307 {
308     size_t fontCount = 0;
309     ss.write(reinterpret_cast<const char*>(&fontCount), sizeof(fontCount));
310 
311     std::lock_guard<std::mutex> lock(mapMutex_);
312     for (auto co : typefaceHashCode_) {
313         if (typefaceHashMap_.find(co.second) != typefaceHashMap_.end()) {
314             auto [typeface, ref] = typefaceHashMap_.at(co.second);
315 
316             if (auto data = typeface->Serialize()) {
317                 const void* stream = data->GetData();
318                 size_t size = data->GetSize();
319 
320                 ss.write(reinterpret_cast<const char*>(&co.first), sizeof(co.first));
321                 ss.write(reinterpret_cast<const char*>(&size), sizeof(size));
322                 ss.write(reinterpret_cast<const char*>(stream), size);
323                 fontCount++;
324             }
325         }
326     }
327 
328     ss.seekp(0, std::ios_base::beg);
329     ss.write(reinterpret_cast<const char*>(&fontCount), sizeof(fontCount));
330     ss.seekp(0, std::ios_base::end);
331 }
332 
ReplayDeserialize(std::stringstream & ss)333 std::string RSTypefaceCache::ReplayDeserialize(std::stringstream& ss)
334 {
335     constexpr int bitNumber = 30 + 32;
336     uint64_t replayMask = (uint64_t)1 << bitNumber;
337     size_t fontCount;
338     uint64_t uniqueId;
339     size_t dataSize;
340     std::vector<uint8_t> data;
341     constexpr size_t maxTypefaceDataSize = 40'000'000;
342 
343     ss.read(reinterpret_cast<char*>(&fontCount), sizeof(fontCount));
344     for (size_t i = 0; i < fontCount; i++) {
345         ss.read(reinterpret_cast<char*>(&uniqueId), sizeof(uniqueId));
346         ss.read(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
347 
348         if (dataSize > maxTypefaceDataSize) {
349             return "Typeface serialized data is over 40MB";
350         }
351         data.resize(dataSize);
352         ss.read(reinterpret_cast<char*>(data.data()), data.size());
353 
354         if (ss.eof()) {
355             return "Typeface track damaged";
356         }
357 
358         std::shared_ptr<Drawing::Typeface> typeface;
359         typeface = Drawing::Typeface::Deserialize(data.data(), data.size());
360         if (typeface) {
361             uniqueId |= replayMask;
362             CacheDrawingTypeface(uniqueId, typeface);
363         } else {
364             return "Typeface unmarshalling failed";
365         }
366     }
367     return {};
368 }
369 
ReplayClear()370 void RSTypefaceCache::ReplayClear()
371 {
372     std::vector<uint64_t> removeId;
373     constexpr int bitNumber = 30 + 32;
374     uint64_t replayMask = (uint64_t)1 << bitNumber;
375     {
376         std::lock_guard<std::mutex> lock(mapMutex_);
377         for (auto co : typefaceHashCode_) {
378             if (co.first & replayMask) {
379                 removeId.emplace_back(co.first);
380             }
381         }
382     }
383     for (auto uniqueId : removeId) {
384         RemoveDrawingTypefaceByGlobalUniqueId(uniqueId);
385     }
386 }
387 
388 } // namespace Rosen
389 } // namespace OHOS
390