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