1 /*
2 * Copyright (c) 2020-2021 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 "imgdecode/cache_manager.h"
17 #include "gfx_utils/graphic_log.h"
18 #include "hal_tick.h"
19 #include "securec.h"
20
21 namespace OHOS {
GetImgData() const22 const uint8_t* CacheEntry::GetImgData() const
23 {
24 return dsc_.imgInfo.data;
25 }
26
ReadLine(const Point & start,int16_t len,uint8_t * buf)27 RetCode CacheEntry::ReadLine(const Point& start, int16_t len, uint8_t* buf)
28 {
29 RetCode ret;
30 if (dsc_.decoder != nullptr) {
31 ret = dsc_.decoder->ReadLine(dsc_, start, len, buf);
32 } else {
33 ret = RetCode::FAIL;
34 }
35
36 return ret;
37 }
38
Clear()39 void CacheEntry::Clear()
40 {
41 if (dsc_.decoder != nullptr) {
42 dsc_.decoder->Close(dsc_);
43 }
44
45 dsc_.decoder = nullptr;
46 ClearSrc();
47 dsc_.imgInfo.data = nullptr;
48 dsc_.fd = -1;
49 dsc_.srcType = IMG_SRC_UNKNOWN;
50 life_ = 0;
51 }
52
ClearSrc()53 void CacheEntry::ClearSrc()
54 {
55 if (dsc_.srcType == IMG_SRC_FILE) {
56 UIFree(const_cast<char*>(dsc_.path));
57 }
58 dsc_.path = nullptr;
59 }
60
SetSrc(const char * path)61 RetCode CacheEntry::SetSrc(const char* path)
62 {
63 ClearSrc();
64 if (dsc_.srcType == IMG_SRC_FILE) {
65 size_t strLen = strlen(path);
66 if (strLen > MAX_SRC_LENGTH) {
67 return RetCode::FAIL;
68 }
69 char* newStr = static_cast<char*>(UIMalloc(static_cast<uint32_t>(strLen) + 1));
70 if (newStr == nullptr) {
71 return RetCode::FAIL;
72 }
73 if (memcpy_s(newStr, strLen + 1, path, strLen) != EOK) {
74 UIFree(reinterpret_cast<void*>(newStr));
75 newStr = nullptr;
76 return RetCode::FAIL;
77 }
78 newStr[strLen] = '\0';
79 dsc_.path = newStr;
80 } else {
81 dsc_.path = path;
82 }
83 return RetCode::OK;
84 }
85
GetInstance()86 CacheManager& CacheManager::GetInstance()
87 {
88 static CacheManager instance;
89 return instance;
90 }
91
Init(uint16_t size)92 RetCode CacheManager::Init(uint16_t size)
93 {
94 if ((size == 0) || (size > DEFAULT_MAX_CACHE_ENTRY_NUM)) {
95 return RetCode::FAIL;
96 }
97 Reset();
98 if (entryArr_ != nullptr) {
99 UIFree(reinterpret_cast<void*>(entryArr_));
100 }
101
102 uint32_t tmpCacheSize = size * sizeof(CacheEntry);
103 entryArr_ = static_cast<CacheEntry*>(UIMalloc(tmpCacheSize));
104 if (entryArr_ == nullptr) {
105 size_ = 0;
106 return RetCode::FAIL;
107 }
108
109 if (memset_s(entryArr_, tmpCacheSize, 0, tmpCacheSize) != EOK) {
110 UIFree(reinterpret_cast<void*>(entryArr_));
111 entryArr_ = nullptr;
112 return RetCode::FAIL;
113 }
114
115 size_ = size;
116 return RetCode::OK;
117 }
118
Open(const char * path,const Style & style,CacheEntry & entry)119 RetCode CacheManager::Open(const char* path, const Style& style, CacheEntry& entry)
120 {
121 if ((path == nullptr) || (GetSize() <= 0)) {
122 return RetCode::FAIL;
123 }
124
125 AgingAll();
126 uint16_t indexHitted = 0;
127 RetCode ret = GetIndex(path, indexHitted);
128 if (ret == RetCode::OK) {
129 ReadToCache(entryArr_[indexHitted]);
130 entry = entryArr_[indexHitted];
131 return RetCode::OK;
132 }
133
134 SelectEntryToReplace(indexHitted);
135 if ((entryArr_[indexHitted].dsc_.path != nullptr) && (entryArr_[indexHitted].dsc_.decoder != nullptr)) {
136 entryArr_[indexHitted].dsc_.decoder->Close(entryArr_[indexHitted].dsc_);
137 }
138
139 uint32_t startTime = HALTick::GetInstance().GetTime();
140 entryArr_[indexHitted].life_ = 0;
141
142 ret = TryDecode(path, style, entryArr_[indexHitted]);
143 if (ret != RetCode::OK) {
144 return ret;
145 }
146 ReadToCache(entryArr_[indexHitted]);
147 entryArr_[indexHitted].life_ = HALTick::GetInstance().GetElapseTime(startTime);
148 entry = entryArr_[indexHitted];
149 return RetCode::OK;
150 }
151
Close(const char * path)152 RetCode CacheManager::Close(const char* path)
153 {
154 if (path == nullptr) {
155 return RetCode::FAIL;
156 }
157
158 for (uint16_t index = 0; index < GetSize(); index++) {
159 if (entryArr_[index].dsc_.srcType == IMG_SRC_FILE) {
160 if (entryArr_[index].dsc_.path == nullptr) {
161 continue;
162 }
163 if (strcmp(entryArr_[index].dsc_.path, path) == 0) {
164 Clear(entryArr_[index]);
165 break;
166 }
167 } else {
168 if (entryArr_[index].dsc_.path == path) {
169 Clear(entryArr_[index]);
170 break;
171 }
172 }
173 }
174
175 return RetCode::OK;
176 }
177
GetImageHeader(const char * path,ImageHeader & header)178 bool CacheManager::GetImageHeader(const char* path, ImageHeader& header)
179 {
180 CacheEntry entry;
181 Style useless;
182 RetCode ret = Open(path, useless, entry);
183 if (ret != RetCode::OK) {
184 GRAPHIC_LOGW("CacheManager::GetImageHeader Image get info found unknown src type\n");
185 return false;
186 }
187
188 header = entry.GetImgHeader();
189 return true;
190 }
191
Reset()192 RetCode CacheManager::Reset()
193 {
194 if (entryArr_ == nullptr) {
195 return RetCode::OK;
196 }
197
198 for (uint16_t index = 0; index < GetSize(); index++) {
199 if (entryArr_[index].dsc_.path != nullptr) {
200 Clear(entryArr_[index]);
201 }
202 }
203
204 return RetCode::OK;
205 }
206
ReadToCache(CacheEntry & entry)207 RetCode CacheManager::ReadToCache(CacheEntry& entry)
208 {
209 if (entry.dsc_.decoder == nullptr) {
210 return RetCode::FAIL;
211 }
212 return entry.dsc_.decoder->ReadToCache(entry.dsc_);
213 }
214
Clear(CacheEntry & entry)215 void CacheManager::Clear(CacheEntry& entry)
216 {
217 entry.Clear();
218 }
219
AgingAll(int32_t time)220 void CacheManager::AgingAll(int32_t time)
221 {
222 for (uint16_t index = 0; index < GetSize(); index++) {
223 if (entryArr_[index].life_ > INT32_MIN + AGING_INTERVAL) {
224 entryArr_[index].life_ -= time;
225 }
226 }
227 }
228
GetIndex(const char * path,uint16_t & hittedIndex)229 RetCode CacheManager::GetIndex(const char* path, uint16_t& hittedIndex)
230 {
231 for (uint16_t index = 0; index < GetSize(); index++) {
232 if (entryArr_[index].dsc_.srcType == IMG_SRC_FILE) {
233 if ((entryArr_[index].dsc_.path != nullptr) && !strcmp(path, entryArr_[index].dsc_.path)) {
234 entryArr_[index].life_ += entryArr_[index].dsc_.timeToOpen * LIFE_GAIN_INTERVAL;
235 if (entryArr_[index].life_ > LIFE_LIMIT) {
236 entryArr_[index].life_ = LIFE_LIMIT;
237 }
238 hittedIndex = index;
239 return RetCode::OK;
240 }
241 } else {
242 ImageInfo* imgDsc = reinterpret_cast<ImageInfo*>(const_cast<char*>(path));
243 if ((entryArr_[index].dsc_.path == path) && (entryArr_[index].dsc_.imgInfo.data == imgDsc->data)) {
244 entryArr_[index].life_ += entryArr_[index].dsc_.timeToOpen * LIFE_GAIN_INTERVAL;
245 if (entryArr_[index].life_ > LIFE_LIMIT) {
246 entryArr_[index].life_ = LIFE_LIMIT;
247 }
248 hittedIndex = index;
249 return RetCode::OK;
250 }
251 }
252 }
253
254 return RetCode::FAIL;
255 }
256
SelectEntryToReplace(uint16_t & selectedIndex)257 RetCode CacheManager::SelectEntryToReplace(uint16_t& selectedIndex)
258 {
259 selectedIndex = 0;
260 for (uint16_t index = 0; index < GetSize(); index++) {
261 if (entryArr_[index].life_ < entryArr_[selectedIndex].life_) {
262 selectedIndex = index;
263 }
264 }
265
266 return RetCode::OK;
267 }
268
TryDecode(const char * path,const Style & style,CacheEntry & entry)269 RetCode CacheManager::TryDecode(const char* path, const Style& style, CacheEntry& entry)
270 {
271 FileImgDecoder* decoder = &(FileImgDecoder::GetInstance());
272 if (decoder == nullptr) {
273 Clear(entry);
274 return RetCode::FAIL;
275 }
276
277 entry.dsc_.srcType = IMG_SRC_FILE;
278 RetCode ret = entry.SetSrc(path);
279 if (ret != RetCode::OK) {
280 Clear(entry);
281 return ret;
282 }
283 entry.dsc_.decoder = decoder;
284
285 ret = entry.dsc_.decoder->GetHeader(entry.dsc_);
286 if (ret != RetCode::OK) {
287 Clear(entry);
288 return ret;
289 }
290
291 ret = entry.dsc_.decoder->Open(entry.dsc_);
292 if (ret != RetCode::OK) {
293 Clear(entry);
294 return ret;
295 }
296
297 return ret;
298 }
299 } // namespace OHOS
300