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