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