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