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