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