• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 "form_cache_mgr.h"
17 
18 #include <sstream>
19 
20 #include "fms_log_wrapper.h"
21 #include "nlohmann/json.hpp"
22 #include "scope_guard.h"
23 
24 namespace OHOS {
25 namespace AppExecFwk {
26 namespace {
27 const std::string JSON_EMPTY_STRING = "{}";
28 const std::string JSON_NULL_STRING = "null";
29 
30 const std::string FORM_CACHE_TABLE = "form_cache";
31 const std::string FORM_ID = "FORM_ID";
32 const std::string DATA_CACHE = "DATA_CACHE";
33 const int32_t DATA_CACHE_INDEX = 1;
34 const std::string FORM_IMAGES = "FORM_IMAGES";
35 const int32_t FORM_IMAGES_INDEX = 2;
36 const std::string CACHE_STATE = "CACHE_STATE";
37 const int32_t CACHE_STATE_INDEX = 3;
38 
39 const std::string IMG_CACHE_TABLE = "img_cache";
40 const std::string IMAGE_ID = "IMAGE_ID";
41 const int32_t IMAGE_ID_INDEX = 0;
42 const std::string IMAGE_BIT = "IMAGE_BIT";
43 const int32_t IMAGE_BIT_INDEX = 1;
44 const std::string IMAGE_SIZE = "IMAGE_SIZE";
45 const int32_t IMAGE_SIZE_INDEX = 2;
46 
47 const int32_t INVALID_INDEX = -1;
48 
HasContent(const std::string & str)49 inline bool HasContent(const std::string &str)
50 {
51     return !str.empty() && str != JSON_EMPTY_STRING && str != JSON_NULL_STRING;
52 }
53 }
54 
FormCacheMgr()55 FormCacheMgr::FormCacheMgr()
56 {
57     HILOG_INFO("create form cache manager instance");
58     CreateFormCacheTable();
59 }
60 
~FormCacheMgr()61 FormCacheMgr::~FormCacheMgr()
62 {
63     HILOG_INFO("destroy form cache manager instance");
64 }
65 
CreateFormCacheTable()66 void FormCacheMgr::CreateFormCacheTable()
67 {
68     FormRdbConfig formRdbConfig;
69     formRdbConfig.tableName = FORM_CACHE_TABLE;
70     formRdbConfig.createTableSql = "CREATE TABLE IF NOT EXISTS " + FORM_CACHE_TABLE
71         + " (FORM_ID TEXT NOT NULL PRIMARY KEY, DATA_CACHE TEXT, FORM_IMAGES TEXT, CACHE_STATE INTEGER);";
72     rdbDataManager_ = std::make_shared<FormRdbDataMgr>(formRdbConfig);
73     rdbDataManager_->Init();
74     std::string createImgCacheTableSql = "CREATE TABLE IF NOT EXISTS " + IMG_CACHE_TABLE
75         + " (IMAGE_ID INTEGER PRIMARY KEY AUTOINCREMENT, IMAGE_BIT BLOB, IMAGE_SIZE TEXT);";
76     rdbDataManager_->ExecuteSql(createImgCacheTableSql);
77 }
78 
Start()79 void FormCacheMgr::Start()
80 {
81     HILOG_INFO("FormCacheMgr Start.");
82     ResetCacheStateAfterReboot();
83 }
84 
GetData(const int64_t formId,std::string & data,std::map<std::string,std::pair<sptr<FormAshmem>,int32_t>> & imageDataMap) const85 bool FormCacheMgr::GetData(const int64_t formId, std::string &data,
86     std::map<std::string, std::pair<sptr<FormAshmem>, int32_t>> &imageDataMap) const
87 {
88     HILOG_DEBUG("GetData start");
89     std::lock_guard<std::mutex> lock(cacheMutex_);
90     FormCache formCache;
91     formCache.formId = formId;
92     bool ret = GetDataCacheFromDb(formId, formCache);
93     if (!ret) {
94         HILOG_ERROR("GetData failed, no data in db.");
95         return false;
96     }
97 
98     bool hasContent = false;
99     if (HasContent(formCache.dataCache)) {
100         nlohmann::json dataCacheObj = nlohmann::json::parse(formCache.dataCache, nullptr, false);
101         if (dataCacheObj.is_discarded() || !dataCacheObj.is_object()) {
102             HILOG_ERROR("GetData failed due to dataCache is discarded.");
103             return false;
104         }
105 
106         data = formCache.dataCache;
107         hasContent = true;
108     }
109 
110     if (HasContent(formCache.imgCache)) {
111         ret = InnerGetImageData(formCache, imageDataMap);
112         if (!ret) {
113             HILOG_ERROR("InnerGetImageData failed.");
114             return false;
115         }
116 
117         hasContent = true;
118     }
119 
120     return hasContent;
121 }
122 
InnerGetImageData(const FormCache & formCache,std::map<std::string,std::pair<sptr<FormAshmem>,int32_t>> & imageDataMap) const123 bool FormCacheMgr::InnerGetImageData(
124     const FormCache &formCache,
125     std::map<std::string, std::pair<sptr<FormAshmem>, int32_t>> &imageDataMap) const
126 {
127     HILOG_DEBUG("InnerGetImageData start");
128     nlohmann::json imgCacheObj = nlohmann::json::parse(formCache.imgCache, nullptr, false);
129     if (imgCacheObj.is_discarded() || !imgCacheObj.is_object()) {
130         HILOG_ERROR("imgCacheObj is discarded.");
131         return false;
132     }
133 
134     for (auto && [key, value] : imgCacheObj.items()) {
135         int64_t rowId;
136         std::stringstream ss;
137         ss << value.dump();
138         ss >> rowId;
139         std::vector<uint8_t> blob;
140         int32_t size = 0;
141         if (!GetImgCacheFromDb(rowId, blob, size)) {
142             HILOG_ERROR("GetImgCacheFromDb failed.");
143             return false;
144         }
145 
146         sptr<FormAshmem> formAshmem = new (std::nothrow) FormAshmem();
147         if (formAshmem == nullptr) {
148             HILOG_ERROR("Alloc ashmem failed");
149             return false;
150         }
151 
152         if (!formAshmem->WriteToAshmem(key, reinterpret_cast<char *>(blob.data()), size)) {
153             HILOG_ERROR("Write to ashmem failed");
154             return false;
155         }
156 
157         imageDataMap[key] = std::make_pair(formAshmem, size);
158     }
159 
160     return true;
161 }
162 
AddData(int64_t formId,const FormProviderData & formProviderData)163 bool FormCacheMgr::AddData(int64_t formId, const FormProviderData &formProviderData)
164 {
165     HILOG_INFO("AddData start, formId:%{public}" PRId64 "", formId);
166     std::lock_guard<std::mutex> lock(cacheMutex_);
167 
168     FormCache formCache;
169     formCache.formId = formId;
170     GetDataCacheFromDb(formId, formCache);
171     if (!AddImgData(formProviderData, formCache)) {
172         HILOG_ERROR("AddImgData failed.");
173         return false;
174     }
175 
176     if (!AddCacheData(formProviderData, formCache)) {
177         HILOG_ERROR("AddCacheData failed.");
178         return false;
179     }
180 
181     // Save dataCache and imgCache
182     formCache.cacheState = CacheState::DEFAULT;
183     return SaveDataCacheToDb(formId, formCache);
184 }
185 
AddImgData(const FormProviderData & formProviderData,FormCache & formCache)186 bool FormCacheMgr::AddImgData(
187     const FormProviderData &formProviderData, FormCache &formCache)
188 {
189     nlohmann::json newImgDbData;
190     if (!AddImgDataToDb(formProviderData, newImgDbData)) {
191         HILOG_ERROR("AddImgDataToDb failed.");
192         return false;
193     }
194 
195     if (newImgDbData.empty()) {
196         HILOG_INFO("No new imgData.");
197         return true;
198     }
199 
200     if (!HasContent(formCache.imgCache)) {
201         // No imgCache in db
202         formCache.imgCache = newImgDbData.dump();
203         return true;
204     }
205 
206     nlohmann::json imgCacheObj = nlohmann::json::parse(formCache.imgCache, nullptr, false);
207     if (imgCacheObj.is_discarded() || !imgCacheObj.is_object()) {
208         HILOG_ERROR("failed to parse data.");
209         return false;
210     }
211 
212     // Update imgCache
213     for (auto && [key, value] : newImgDbData.items()) {
214         if (imgCacheObj.find(key) != imgCacheObj.end()) {
215             DeleteImgCacheInDb(imgCacheObj[key].dump());
216         }
217 
218         imgCacheObj[key] = value;
219     }
220 
221     formCache.imgCache = imgCacheObj.dump();
222     return true;
223 }
224 
AddCacheData(const FormProviderData & formProviderData,FormCache & formCache)225 bool FormCacheMgr::AddCacheData(
226     const FormProviderData &formProviderData, FormCache &formCache)
227 {
228     auto newDataStr = formProviderData.GetDataString();
229     nlohmann::json newDataObj;
230     if (HasContent(newDataStr)) {
231         newDataObj = nlohmann::json::parse(newDataStr, nullptr, false);
232         if (newDataObj.is_discarded() || !newDataObj.is_object()) {
233             HILOG_ERROR("failed to parse data.");
234             return false;
235         }
236 
237         newDataObj.erase("formImages");
238     }
239 
240     if (newDataObj.empty()) {
241         HILOG_INFO("No new cacheData.");
242         return true;
243     }
244 
245     if (!HasContent(formCache.dataCache)) {
246         // No dataCache in db
247         formCache.dataCache = newDataObj.dump();
248         return true;
249     }
250 
251     nlohmann::json dataCacheObj = nlohmann::json::parse(formCache.dataCache, nullptr, false);
252     if (dataCacheObj.is_discarded() || !dataCacheObj.is_object()) {
253         HILOG_ERROR("failed to parse data.");
254         return false;
255     }
256 
257     // Update dataCache
258     for (auto && [key, value] : newDataObj.items()) {
259         dataCacheObj[key] = value;
260     }
261     formCache.dataCache = dataCacheObj.dump();
262     return true;
263 }
264 
AddImgDataToDb(const FormProviderData & formProviderData,nlohmann::json & imgDataJson)265 bool FormCacheMgr::AddImgDataToDb(
266     const FormProviderData &formProviderData, nlohmann::json &imgDataJson)
267 {
268     auto imgCache = formProviderData.GetImageDataMap();
269     HILOG_DEBUG("AddImgDataToDb imgCache size: %{public}zu.", imgCache.size());
270     for (const auto &iter : imgCache) {
271         int64_t rowId = INVALID_INDEX;
272         std::vector<uint8_t> value;
273         bool ret = GetImageDataFromAshmem(
274             iter.first, iter.second.first->GetAshmem(), iter.second.first->GetAshmemSize(), value);
275         if (!ret) {
276             HILOG_ERROR("failed to get img data imgName: %{public}s.", iter.first.c_str());
277             return false;
278         }
279 
280         ret = SaveImgCacheToDb(value, iter.second.second, rowId);
281         if (!ret || rowId == INVALID_INDEX) {
282             HILOG_ERROR("failed to save img data imgName: %{public}s.", iter.first.c_str());
283             return false;
284         }
285 
286         imgDataJson[iter.first] = rowId;
287     }
288 
289     return true;
290 }
291 
GetImageDataFromAshmem(const std::string & picName,const sptr<Ashmem> & ashmem,int32_t len,std::vector<uint8_t> & value)292 bool FormCacheMgr::GetImageDataFromAshmem(
293     const std::string& picName, const sptr<Ashmem> &ashmem, int32_t len, std::vector<uint8_t> &value)
294 {
295     HILOG_DEBUG("GetImageDataFromAshmem start picName: %{public}s.", picName.c_str());
296     if (ashmem == nullptr) {
297         HILOG_ERROR("ashmem is null when picName: %{public}s", picName.c_str());
298         return false;
299     }
300 
301     bool ret = ashmem->MapReadOnlyAshmem();
302     if (!ret) {
303         HILOG_ERROR("MapReadOnlyAshmem fail, fail reason: %{public}s, picName: %{public}s",
304             strerror(errno), picName.c_str());
305         return false;
306     }
307 
308     ScopeGuard stateGuard([ashmem] {
309         if (ashmem) {
310             ashmem->UnmapAshmem();
311         }
312     });
313     const uint8_t* imageData = reinterpret_cast<const uint8_t*>(ashmem->ReadFromAshmem(len, 0));
314     if (imageData == nullptr) {
315         HILOG_ERROR("ReadFromAshmem failed picName: %{public}s", picName.c_str());
316         return false;
317     }
318 
319     value = std::vector<uint8_t>(imageData, imageData + len);
320     return true;
321 }
322 
DeleteData(const int64_t formId)323 bool FormCacheMgr::DeleteData(const int64_t formId)
324 {
325     HILOG_INFO("DeleteData start, formId:%{public}" PRId64" ", formId);
326     std::lock_guard<std::mutex> lock(cacheMutex_);
327     FormCache formCache;
328     bool ret = GetDataCacheFromDb(formId, formCache);
329     if (!ret) {
330         HILOG_INFO("No DataCache when delete.");
331         return true;
332     }
333 
334     InnerDeleteImageData(formCache);
335     return DeleteDataCacheInDb(formId);
336 }
337 
NeedAcquireProviderData(const int64_t formId) const338 bool FormCacheMgr::NeedAcquireProviderData(const int64_t formId) const
339 {
340     HILOG_DEBUG("NeedAcquireProviderData");
341     FormCache formCache;
342     bool ret = GetDataCacheFromDb(formId, formCache);
343     if (!ret) {
344         HILOG_ERROR("No DataCache.");
345         return true;
346     }
347 
348     bool hasContent = HasContent(formCache.dataCache) || HasContent(formCache.imgCache);
349     bool isRebootState = formCache.cacheState == CacheState::REBOOT;
350     return !hasContent || isRebootState;
351 }
352 
GetDataCacheFromDb(int64_t formId,FormCache & formCache) const353 bool FormCacheMgr::GetDataCacheFromDb(int64_t formId, FormCache &formCache) const
354 {
355     NativeRdb::AbsRdbPredicates absRdbPredicates(FORM_CACHE_TABLE);
356     absRdbPredicates.EqualTo(FORM_ID, std::to_string(formId));
357     auto absSharedResultSet = rdbDataManager_->QueryData(absRdbPredicates);
358     if (absSharedResultSet == nullptr) {
359         HILOG_ERROR("GetDataCacheFromDb failed.");
360         return false;
361     }
362 
363     ScopeGuard stateGuard([absSharedResultSet] {
364         if (absSharedResultSet) {
365             absSharedResultSet->Close();
366         }
367     });
368     if (!absSharedResultSet->HasBlock()) {
369         HILOG_ERROR("absSharedResultSet has no block");
370         return false;
371     }
372 
373     int ret = absSharedResultSet->GoToFirstRow();
374     if (ret != NativeRdb::E_OK) {
375         HILOG_ERROR("GoToFirstRow failed, ret: %{public}d", ret);
376         return false;
377     }
378 
379     ret = absSharedResultSet->GetString(DATA_CACHE_INDEX, formCache.dataCache);
380     if (ret != NativeRdb::E_OK) {
381         HILOG_DEBUG("GetString dataCache failed, ret: %{public}d", ret);
382     }
383 
384     ret = absSharedResultSet->GetString(FORM_IMAGES_INDEX, formCache.imgCache);
385     if (ret != NativeRdb::E_OK) {
386         HILOG_DEBUG("GetString imgCache failed, ret: %{public}d", ret);
387     }
388 
389     int32_t cacheState;
390     ret = absSharedResultSet->GetInt(CACHE_STATE_INDEX, cacheState);
391     if (ret != NativeRdb::E_OK) {
392         HILOG_DEBUG("GetInt cacheState failed, ret: %{public}d", ret);
393     }
394     formCache.cacheState = static_cast<CacheState>(cacheState);
395     return true;
396 }
397 
SaveDataCacheToDb(int64_t formId,const FormCache & formCache)398 bool FormCacheMgr::SaveDataCacheToDb(int64_t formId, const FormCache &formCache)
399 {
400     NativeRdb::ValuesBucket valuesBucket;
401     valuesBucket.PutString(FORM_ID, std::to_string(formId));
402     valuesBucket.PutString(DATA_CACHE, formCache.dataCache);
403     valuesBucket.PutString(FORM_IMAGES, formCache.imgCache);
404     valuesBucket.PutInt(CACHE_STATE, static_cast<int>(formCache.cacheState));
405     int64_t rowId;
406     bool ret = rdbDataManager_->InsertData(FORM_CACHE_TABLE, valuesBucket, rowId);
407     if (!ret) {
408         HILOG_ERROR("SaveDataCacheToDb formId:%{public}s failed.", std::to_string(formId).c_str());
409         return false;
410     }
411     return true;
412 }
413 
InnerDeleteImageData(const FormCache & formCache)414 bool FormCacheMgr::InnerDeleteImageData(const FormCache &formCache)
415 {
416     if (!HasContent(formCache.imgCache)) {
417         HILOG_INFO("Has no imgCache when delete.");
418         return true;
419     }
420 
421     nlohmann::json imgCacheObj = nlohmann::json::parse(formCache.imgCache, nullptr, false);
422     if (imgCacheObj.is_discarded() || !imgCacheObj.is_object()) {
423         HILOG_ERROR("failed to parse data.");
424         return false;
425     }
426 
427     for (auto && [key, value] : imgCacheObj.items()) {
428         DeleteImgCacheInDb(value.dump());
429     }
430 
431     return true;
432 }
433 
DeleteDataCacheInDb(int64_t formId)434 bool FormCacheMgr::DeleteDataCacheInDb(int64_t formId)
435 {
436     NativeRdb::AbsRdbPredicates absRdbPredicates(FORM_CACHE_TABLE);
437     absRdbPredicates.EqualTo(FORM_ID, std::to_string(formId));
438     return rdbDataManager_->DeleteData(absRdbPredicates);
439 }
440 
GetImgCacheFromDb(int64_t rowId,std::vector<uint8_t> & blob,int32_t & size) const441 bool FormCacheMgr::GetImgCacheFromDb(
442     int64_t rowId, std::vector<uint8_t> &blob, int32_t &size) const
443 {
444     NativeRdb::AbsRdbPredicates absRdbPredicates(IMG_CACHE_TABLE);
445     absRdbPredicates.EqualTo(IMAGE_ID, std::to_string(rowId));
446     auto absSharedResultSet = rdbDataManager_->QueryData(absRdbPredicates);
447     if (absSharedResultSet == nullptr) {
448         HILOG_ERROR("GetImgCacheFromDb failed.");
449         return false;
450     }
451 
452     ScopeGuard stateGuard([absSharedResultSet] {
453         if (absSharedResultSet) {
454             absSharedResultSet->Close();
455         }
456     });
457     if (!absSharedResultSet->HasBlock()) {
458         HILOG_ERROR("absSharedResultSet has no block");
459         return false;
460     }
461 
462     int ret = absSharedResultSet->GoToFirstRow();
463     if (ret != NativeRdb::E_OK) {
464         HILOG_ERROR("GoToFirstRow failed, ret: %{public}d", ret);
465         return false;
466     }
467 
468     ret = absSharedResultSet->GetBlob(IMAGE_BIT_INDEX, blob);
469     if (ret != NativeRdb::E_OK) {
470         HILOG_ERROR("GetBlob failed, ret: %{public}d", ret);
471         return false;
472     }
473 
474     ret = absSharedResultSet->GetInt(IMAGE_SIZE_INDEX, size);
475     if (ret != NativeRdb::E_OK) {
476         HILOG_ERROR("GetInt size failed, ret: %{public}d", ret);
477         return false;
478     }
479 
480     return true;
481 }
482 
SaveImgCacheToDb(const std::vector<uint8_t> & value,int32_t size,int64_t & rowId)483 bool FormCacheMgr::SaveImgCacheToDb(const std::vector<uint8_t> &value, int32_t size, int64_t &rowId)
484 {
485     NativeRdb::ValuesBucket valuesBucket;
486     valuesBucket.PutBlob(IMAGE_BIT, value);
487     valuesBucket.PutInt(IMAGE_SIZE, size);
488     bool ret = rdbDataManager_->InsertData(IMG_CACHE_TABLE, valuesBucket, rowId);
489     if (!ret) {
490         HILOG_ERROR("SaveImgCacheToDb failed.");
491         return false;
492     }
493     return true;
494 }
495 
DeleteImgCacheInDb(const std::string & rowId)496 bool FormCacheMgr::DeleteImgCacheInDb(const std::string &rowId)
497 {
498     if (rowId.empty()) {
499         return false;
500     }
501 
502     NativeRdb::AbsRdbPredicates absRdbPredicates(IMG_CACHE_TABLE);
503     absRdbPredicates.EqualTo(IMAGE_ID, rowId);
504     return rdbDataManager_->DeleteData(absRdbPredicates);
505 }
506 
ResetCacheStateAfterReboot()507 void FormCacheMgr::ResetCacheStateAfterReboot()
508 {
509     std::string sql = "UPDATE " + FORM_CACHE_TABLE + " SET " + CACHE_STATE + " = 1;";
510     rdbDataManager_->ExecuteSql(sql);
511 }
512 }  // namespace AppExecFwk
513 }  // namespace OHOS
514