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