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