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