1 /*
2 * Copyright (c) 2022 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 "cache_data.h"
17 #include <cerrno>
18 #include <chrono>
19 #include <sys/mman.h>
20 #include <sys/stat.h>
21 #include <cstring>
22 #include <securec.h>
23 #include "render_context_log.h"
24
25 namespace OHOS {
26 const char* RS_CACHE_MAGIC_HEAD = "OHRS";
27 const int RS_CACHE_MAGIC_HEAD_LEN = 4;
28 const int RS_CACHE_HEAD_LEN = 8;
29 const int RS_BYTE_SIZE = 8;
30 namespace Rosen {
CacheData(const size_t maxKeySize,const size_t maxValueSize,const size_t maxTotalSize,const std::string & fileName)31 CacheData::CacheData(const size_t maxKeySize, const size_t maxValueSize,
32 const size_t maxTotalSize, const std::string& fileName)
33 : maxKeySize_(maxKeySize),
34 maxValueSize_(maxValueSize),
35 maxTotalSize_(maxTotalSize),
36 cacheDir_(fileName) {}
37
~CacheData()38 CacheData::~CacheData() {}
39
CrcGen(const uint8_t * buffer,size_t bufferSize)40 uint32_t CacheData::CrcGen(const uint8_t *buffer, size_t bufferSize)
41 {
42 const uint32_t polynoimal = 0xEDB88320;
43 uint32_t crc = 0xFFFFFFFF;
44
45 for (size_t i = 0; i < bufferSize ; ++i) {
46 crc ^= (static_cast<uint32_t>(buffer[i]));
47 for (size_t j = 0; j < RS_BYTE_SIZE; ++j) {
48 if (crc & 0x01) {
49 crc = (crc >> 1) ^ polynoimal;
50 } else {
51 crc >>= 1;
52 }
53 }
54 }
55 return crc ^ 0xFFFFFFFF;
56 }
57
IsValidFile(uint8_t * buffer,size_t bufferSize)58 bool CacheData::IsValidFile(uint8_t *buffer, size_t bufferSize)
59 {
60 if (buffer == nullptr) {
61 LOGE("abandon, because of buffer is nullptr");
62 return false;
63 }
64 if (memcmp(buffer, RS_CACHE_MAGIC_HEAD, RS_CACHE_MAGIC_HEAD_LEN) != 0) {
65 LOGE("abandon, because of mismatched RS_CACHE_MAGIC_HEAD");
66 return false;
67 }
68
69 uint32_t* storedCrc = reinterpret_cast<uint32_t*>(buffer + RS_CACHE_MAGIC_HEAD_LEN);
70 uint32_t computedCrc = CrcGen(buffer + RS_CACHE_HEAD_LEN, bufferSize - RS_CACHE_HEAD_LEN);
71 if (computedCrc != *storedCrc) {
72 LOGE("abandon, because of mismatched crc code");
73 return false;
74 }
75
76 return true;
77 }
78
ReadFromFile()79 void CacheData::ReadFromFile()
80 {
81 if (cacheDir_.length() <= 0) {
82 LOGD("abandon, because of empty filename.");
83 return;
84 }
85
86 int fd = open(cacheDir_.c_str(), O_RDONLY, 0);
87 if (fd == ERR_NUMBER) {
88 if (errno != ENOENT) {
89 LOGD("abandon, because fail to open file");
90 }
91 return;
92 }
93 struct stat statBuf;
94 if (fstat(fd, &statBuf) == ERR_NUMBER) {
95 LOGD("abandon, because fail to get the file status");
96 close(fd);
97 return;
98 }
99 if (statBuf.st_size < 0) {
100 LOGD("abandon, negative file size");
101 close(fd);
102 return;
103 }
104
105 size_t fileSize = static_cast<size_t>(statBuf.st_size);
106 if (fileSize < RS_CACHE_HEAD_LEN || fileSize > maxTotalSize_ * maxMultipleSize_ + RS_CACHE_HEAD_LEN) {
107 LOGE("abandon, illegal file size");
108 close(fd);
109 return;
110 }
111 uint8_t *buffer = reinterpret_cast<uint8_t*>(mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0));
112 if (buffer == MAP_FAILED) {
113 LOGD("abandon, because of mmap failure:");
114 close(fd);
115 return;
116 }
117
118 if (!IsValidFile(buffer, fileSize)) {
119 LOGE("abandon, invalid file");
120 munmap(buffer, fileSize);
121 close(fd);
122 return;
123 }
124
125 uint8_t *shaderBuffer = reinterpret_cast<uint8_t*>(buffer + RS_CACHE_HEAD_LEN);
126 if (DeSerialize(shaderBuffer, fileSize - RS_CACHE_HEAD_LEN) < 0) {
127 LOGE("abandon, because fail to read file contents");
128 }
129 munmap(buffer, fileSize);
130 close(fd);
131 }
132
WriteToFile()133 void CacheData::WriteToFile()
134 {
135 if (cacheDir_.length() <= 0) {
136 LOGD("abandon, because of empty filename.");
137 return;
138 }
139 int fd = open(cacheDir_.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
140 if (fd == ERR_NUMBER) {
141 if (errno == EEXIST) {
142 if (unlink(cacheDir_.c_str()) == ERR_NUMBER) {
143 LOGD("abandon, because unlinking the existing file fails");
144 return;
145 }
146 fd = open(cacheDir_.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
147 }
148 if (fd == ERR_NUMBER) {
149 LOGD("abandon, because the file creation fails");
150 return;
151 }
152 }
153 size_t cacheSize = SerializedSize();
154 if (cacheSize <= 0) {
155 LOGD("abandon, illegal serialized size");
156 close(fd);
157 return;
158 }
159 size_t bufferSize = cacheSize + RS_CACHE_HEAD_LEN;
160 uint8_t *buffer = new uint8_t[bufferSize];
161 if (!buffer) {
162 LOGD("abandon, because fail to allocate buffer for cache content");
163 close(fd);
164 unlink(cacheDir_.c_str());
165 return;
166 }
167 if (Serialize(buffer + RS_CACHE_HEAD_LEN, cacheSize) < 0) {
168 LOGD("abandon, because fail to serialize the CacheData:");
169 delete[] buffer;
170 close(fd);
171 unlink(cacheDir_.c_str());
172 return;
173 }
174
175 // Write the file rs magic head and CRC code
176 if (memcpy_s(buffer, bufferSize, RS_CACHE_MAGIC_HEAD, RS_CACHE_MAGIC_HEAD_LEN) != 0) {
177 delete[] buffer;
178 close(fd);
179 unlink(cacheDir_.c_str());
180 return;
181 }
182 uint32_t *crc = reinterpret_cast<uint32_t*>(buffer + RS_CACHE_MAGIC_HEAD_LEN);
183 *crc = CrcGen(buffer + RS_CACHE_HEAD_LEN, cacheSize);
184
185 if (write(fd, buffer, bufferSize) == ERR_NUMBER) {
186 LOGD("abandon, because fail to write to disk");
187 delete[] buffer;
188 close(fd);
189 unlink(cacheDir_.c_str());
190 return;
191 }
192 delete[] buffer;
193 fchmod(fd, S_IRUSR);
194 close(fd);
195 }
196
Rewrite(const void * key,const size_t keySize,const void * value,const size_t valueSize)197 void CacheData::Rewrite(const void *key, const size_t keySize, const void *value, const size_t valueSize)
198 {
199 if (maxKeySize_ < keySize || maxValueSize_ < valueSize ||
200 maxTotalSize_ < keySize + valueSize || keySize == 0 || valueSize <= 0) {
201 LOGD("abandon, because of illegal content size");
202 return;
203 }
204 std::shared_ptr<DataPointer> fakeDataPointer(std::make_shared<DataPointer>(key, keySize, false));
205 ShaderPointer fakeShaderPointer(fakeDataPointer, nullptr);
206 bool isShaderFound = false;
207 size_t newTotalSize = 0;
208 while (!isShaderFound) {
209 auto index = std::lower_bound(shaderPointers_.begin(), shaderPointers_.end(), fakeShaderPointer);
210 if (index == shaderPointers_.end() || fakeShaderPointer < *index) {
211 std::shared_ptr<DataPointer> keyPointer(std::make_shared<DataPointer>(key, keySize, true));
212 std::shared_ptr<DataPointer> valuePointer(std::make_shared<DataPointer>(value, valueSize, true));
213 newTotalSize = totalSize_ + keySize + valueSize;
214 if (IfSizeValidate(newTotalSize, keySize + valueSize)) {
215 shaderPointers_.insert(index, ShaderPointer(keyPointer, valuePointer));
216 totalSize_ = newTotalSize;
217 break;
218 }
219 if (IfSkipClean(keySize + valueSize)) {
220 break;
221 }
222 if (IfCleanFinished()) {
223 continue;
224 }
225 break;
226 } else {
227 std::shared_ptr<DataPointer> valuePointer(std::make_shared<DataPointer>(value, valueSize, true));
228 std::shared_ptr<DataPointer> oldValuePointer(index->GetValuePointer());
229 newTotalSize = totalSize_ + valueSize - oldValuePointer->GetSize();
230 size_t addedSize = (valueSize > oldValuePointer->GetSize()) ? valueSize - oldValuePointer->GetSize() : 0;
231 if (IfSizeValidate(newTotalSize, addedSize)) {
232 index->SetValue(valuePointer);
233 totalSize_ = newTotalSize;
234 break;
235 }
236 if (IfSkipClean(addedSize)) {
237 break;
238 }
239 if (IfCleanFinished()) {
240 continue;
241 }
242 break;
243 }
244 isShaderFound = true;
245 }
246 cleanThreshold_ = 0;
247 }
248
Get(const void * key,const size_t keySize,void * value,const size_t valueSize)249 std::tuple<CacheData::ErrorCode, size_t> CacheData::Get(const void *key, const size_t keySize,
250 void *value, const size_t valueSize)
251 {
252 if (maxKeySize_ < keySize) {
253 LOGD("abandon, because the key is too large");
254 return {ErrorCode::VALUE_SIZE_OVER_MAX_SIZE, 0};
255 }
256 std::shared_ptr<DataPointer> fakeDataPointer(std::make_shared<DataPointer>(key, keySize, false));
257 ShaderPointer fakeShaderPointer(fakeDataPointer, nullptr);
258 auto index = std::lower_bound(shaderPointers_.begin(), shaderPointers_.end(), fakeShaderPointer);
259 if (index == shaderPointers_.end() || fakeShaderPointer < *index) {
260 LOGD("abandon, because no key is found");
261 return {ErrorCode::KEY_NOT_FOUND, 0};
262 }
263 std::shared_ptr <DataPointer> valuePointer(index->GetValuePointer());
264 size_t valuePointerSize = valuePointer->GetSize();
265 if (valuePointerSize > valueSize) {
266 LOGD("abandon, because of insufficient buffer space");
267 return {ErrorCode::VALUE_SIZE_TOO_SAMLL, valuePointerSize};
268 }
269 if (memcpy_s(value, valueSize, valuePointer->GetData(), valuePointerSize)) {
270 LOGD("abandon, failed to copy content");
271 return {ErrorCode::COPY_FAILED, 0};
272 }
273 return {ErrorCode::NO_ERR, valuePointerSize};
274 }
275
SerializedSize() const276 size_t CacheData::SerializedSize() const
277 {
278 size_t size = Align4(sizeof(Header));
279 for (const ShaderPointer &p: shaderPointers_) {
280 std::shared_ptr <DataPointer> const &keyPointer = p.GetKeyPointer();
281 std::shared_ptr <DataPointer> const &valuePointer = p.GetValuePointer();
282 size += Align4(sizeof(ShaderData) + keyPointer->GetSize() + valuePointer->GetSize());
283 }
284 return size;
285 }
286
Serialize(uint8_t * buffer,const size_t size) const287 int CacheData::Serialize(uint8_t *buffer, const size_t size) const
288 {
289 if (size < sizeof(Header)) {
290 LOGD("abandon because of insufficient buffer space.");
291 return -EINVAL;
292 }
293 Header *header = reinterpret_cast<Header *>(buffer);
294 header->numShaders_ = shaderPointers_.size();
295 size_t byteOffset = Align4(sizeof(Header));
296 size_t headSize = sizeof(ShaderData);
297
298 uint8_t *byteBuffer = reinterpret_cast<uint8_t *>(buffer);
299 for (const ShaderPointer &p: shaderPointers_) {
300 std::shared_ptr<DataPointer> const &keyPointer = p.GetKeyPointer();
301 std::shared_ptr<DataPointer> const &valuePointer = p.GetValuePointer();
302 size_t keySize = keyPointer->GetSize();
303 size_t valueSize = valuePointer->GetSize();
304 size_t pairSize = sizeof(ShaderData) + keySize + valueSize;
305 size_t alignedSize = Align4(pairSize);
306 if (byteOffset + alignedSize > size) {
307 LOGD("abandon because of insufficient buffer space.");
308 return -EINVAL;
309 }
310
311 ShaderData *shaderBuffer = reinterpret_cast<ShaderData *>(&byteBuffer[byteOffset]);
312 shaderBuffer->keySize_ = keySize;
313 shaderBuffer->valueSize_ = valueSize;
314 size_t sizeLeft = size - byteOffset - headSize;
315 if (memcpy_s(shaderBuffer->data_, sizeLeft, keyPointer->GetData(), keySize)) {
316 LOGD("abandon, failed to copy key");
317 return -EINVAL;
318 }
319 if (memcpy_s(shaderBuffer->data_ + keySize, sizeLeft - keySize, valuePointer->GetData(), valueSize)) {
320 LOGD("abandon, failed to copy value");
321 return -EINVAL;
322 }
323 if (alignedSize > pairSize) {
324 auto ret = memset_s(shaderBuffer->data_ + keySize + valueSize, alignedSize - pairSize, 0,
325 alignedSize - pairSize);
326 if (ret != EOK) {
327 LOGD("abandon, failed to memset_s");
328 return -EINVAL;
329 }
330 }
331 byteOffset += alignedSize;
332 }
333 return 0;
334 }
335
DeSerialize(uint8_t const * buffer,const size_t size)336 int CacheData::DeSerialize(uint8_t const *buffer, const size_t size)
337 {
338 shaderPointers_.clear();
339 if (size < sizeof(Header)) {
340 LOGD("abandon, not enough room for cache header");
341 }
342
343 if (buffer == nullptr) {
344 LOGD("abandon, buffer is null");
345 return -EINVAL;
346 }
347 const Header *header = reinterpret_cast<const Header *>(buffer);
348 size_t numShaders = header->numShaders_;
349 size_t byteOffset = Align4(sizeof(Header));
350
351 const uint8_t *byteBuffer = reinterpret_cast<const uint8_t *>(buffer);
352 for (size_t i = 0; i < numShaders; i++) {
353 if (byteOffset + sizeof(ShaderData) > size) {
354 shaderPointers_.clear();
355 LOGD("abandon because of insufficient buffer space");
356 return -EINVAL;
357 }
358 const ShaderData *shaderBuffer = reinterpret_cast<const ShaderData *>(&byteBuffer[byteOffset]);
359 size_t keySize = shaderBuffer->keySize_;
360 size_t valueSize = shaderBuffer->valueSize_;
361 size_t pairSize = sizeof(ShaderData) + keySize + valueSize;
362 size_t alignedSize = Align4(pairSize);
363 if (byteOffset + alignedSize > size) {
364 shaderPointers_.clear();
365 LOGD("abandon, not enough room for cache headers");
366 return -EINVAL;
367 }
368
369 const uint8_t *data = shaderBuffer->data_;
370 Rewrite(data, keySize, data + keySize, valueSize);
371 byteOffset += alignedSize;
372 }
373 return 0;
374 }
375
IfSizeValidate(const size_t newSize,const size_t addedSize) const376 bool CacheData::IfSizeValidate(const size_t newSize, const size_t addedSize) const
377 {
378 // check if size is ok and we don't neet to clean the shaders
379 if (newSize <= maxTotalSize_ || addedSize == 0) {
380 return true;
381 }
382 return false;
383 }
384
IfSkipClean(const size_t addedSize) const385 bool CacheData::IfSkipClean(const size_t addedSize) const
386 {
387 // check if the new shader is still too large after cleaning
388 size_t maxPermittedSize = maxTotalSize_ - maxTotalSize_ / cleanLevel_;
389 if (addedSize > maxPermittedSize) {
390 LOGD("new shader is too large, abandon insert");
391 return true;
392 }
393 return false;
394 }
395
IfCleanFinished()396 bool CacheData::IfCleanFinished()
397 {
398 if (!cleanThreshold_) {
399 RandClean(maxTotalSize_ / cleanLevel_);
400 return true;
401 } else {
402 LOGD("abandon, failed to clean the shaders");
403 return false;
404 }
405 }
406
RandClean(const size_t cleanThreshold)407 void CacheData::RandClean(const size_t cleanThreshold)
408 {
409 if (cleanThreshold == 0) {
410 LOGD("CleanThreshold must be > 0");
411 return;
412 }
413 if (cleanThreshold_ == 0) {
414 auto now = std::chrono::steady_clock::now().time_since_epoch().count();
415 if (now < 0) {
416 LOGD("abandon, illegal negative now value");
417 return;
418 }
419 unsigned long currentTime = static_cast<unsigned long>(now);
420 for (int indexRand = 0; indexRand < randLength_; ++indexRand) {
421 cleanInit_[indexRand] = (currentTime >> (indexRand * randShift_)) & 0xFFFF;
422 cleanInit_[indexRand] = (currentTime >> (indexRand * randShift_)) & 0xFFFF;
423 cleanInit_[indexRand] = (currentTime >> (indexRand * randShift_)) & 0xFFFF;
424 }
425 }
426 cleanThreshold_ = cleanThreshold;
427
428 while (totalSize_ > cleanThreshold_) {
429 long int randIndex = nrand48(cleanInit_);
430 if (randIndex < 0) {
431 LOGD("abandon, illegal negative randIndex value");
432 break;
433 }
434 size_t sizeRandIndex = static_cast<size_t>(randIndex);
435 size_t currentSize = shaderPointers_.size();
436 if (currentSize == 0) {
437 LOGD("abandon, shader is empty, nothing to clean");
438 break;
439 }
440 size_t removeIndex = sizeRandIndex % (currentSize);
441 if (!Clean(removeIndex)) {
442 LOGD("abandon, cleaned nothing");
443 break;
444 }
445 }
446 }
447
Clean(const size_t removeIndex)448 size_t CacheData::Clean(const size_t removeIndex)
449 {
450 if (removeIndex >= shaderPointers_.size()) {
451 LOGD("illegal shader index, abandon cleaning");
452 return 0;
453 }
454 const ShaderPointer &shader(shaderPointers_[removeIndex]);
455 size_t reducedSize = shader.GetKeyPointer()->GetSize() + shader.GetValuePointer()->GetSize();
456 totalSize_ -= reducedSize;
457 shaderPointers_.erase(shaderPointers_.begin() + removeIndex);
458 return reducedSize;
459 }
460
DataPointer(const void * data,size_t size,bool ifOccupy)461 CacheData::DataPointer::DataPointer(const void *data, size_t size, bool ifOccupy)
462 : pointer_(nullptr),
463 size_(size),
464 toFree_(ifOccupy)
465 {
466 if (ifOccupy) {
467 pointer_ = malloc(size);
468 } else {
469 pointer_ = data;
470 }
471
472 if (data != nullptr && ifOccupy) {
473 if (memcpy_s(const_cast<void *>(pointer_), size, data, size)) {
474 LOGD("abandon: failed to copy data");
475 return;
476 }
477 }
478 }
479
~DataPointer()480 CacheData::DataPointer::~DataPointer()
481 {
482 if (toFree_) {
483 free(const_cast<void *>(pointer_));
484 pointer_ = nullptr;
485 }
486 }
487
ShaderPointer()488 CacheData::ShaderPointer::ShaderPointer() {}
489
ShaderPointer(const std::shared_ptr<DataPointer> & key,const std::shared_ptr<DataPointer> & value)490 CacheData::ShaderPointer::ShaderPointer(const std::shared_ptr <DataPointer> &key,
491 const std::shared_ptr <DataPointer> &value)
492 : keyPointer_(key),
493 valuePointer_(value) {}
494
ShaderPointer(const ShaderPointer & sp)495 CacheData::ShaderPointer::ShaderPointer(const ShaderPointer &sp)
496 : keyPointer_(sp.keyPointer_),
497 valuePointer_(sp.valuePointer_) {}
498 } // namespace Rosen
499 } // namespace OHOS