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 for (auto && [key, value] : imgCacheObj.items()) {
222 DeleteImgCacheInDb(imgCacheObj[key].dump());
223 }
224 }
225
226 formCache.imgCache = newImgDbData.dump();
227
228 return true;
229 }
230
AddCacheData(const FormProviderData & formProviderData,FormCache & formCache)231 bool FormCacheMgr::AddCacheData(
232 const FormProviderData &formProviderData, FormCache &formCache)
233 {
234 auto newDataStr = formProviderData.GetDataString();
235 nlohmann::json newDataObj;
236 if (HasContent(newDataStr)) {
237 newDataObj = nlohmann::json::parse(newDataStr, nullptr, false);
238 if (newDataObj.is_discarded() || !newDataObj.is_object()) {
239 HILOG_ERROR("parse data failed");
240 return false;
241 }
242
243 newDataObj.erase("formImages");
244 }
245
246 if (newDataObj.empty()) {
247 HILOG_INFO("No new cacheData");
248 return true;
249 }
250
251 if (!HasContent(formCache.dataCache)) {
252 // No dataCache in db
253 formCache.dataCache = newDataObj.dump();
254 return true;
255 }
256
257 nlohmann::json dataCacheObj = nlohmann::json::parse(formCache.dataCache, nullptr, false);
258 if (dataCacheObj.is_discarded() || !dataCacheObj.is_object()) {
259 HILOG_ERROR("parse data failed");
260 return false;
261 }
262
263 // Update dataCache
264 for (auto && [key, value] : newDataObj.items()) {
265 dataCacheObj[key] = value;
266 }
267 formCache.dataCache = dataCacheObj.dump();
268 return true;
269 }
270
AddImgDataToDb(const FormProviderData & formProviderData,nlohmann::json & imgDataJson)271 bool FormCacheMgr::AddImgDataToDb(
272 const FormProviderData &formProviderData, nlohmann::json &imgDataJson)
273 {
274 auto imgCache = formProviderData.GetImageDataMap();
275 HILOG_DEBUG("AddImgDataToDb imgCache size:%{public}zu", imgCache.size());
276 for (const auto &iter : imgCache) {
277 int64_t rowId = INVALID_INDEX;
278 std::vector<uint8_t> value;
279 bool ret = GetImageDataFromAshmem(
280 iter.first, iter.second.first->GetAshmem(), iter.second.first->GetAshmemSize(), value);
281 if (!ret) {
282 HILOG_ERROR("fail get img data imgName:%{public}s", iter.first.c_str());
283 return false;
284 }
285
286 ret = SaveImgCacheToDb(value, iter.second.second, rowId);
287 if (!ret || rowId == INVALID_INDEX) {
288 HILOG_ERROR("fail save img data imgName:%{public}s", iter.first.c_str());
289 return false;
290 }
291
292 imgDataJson[iter.first] = rowId;
293 }
294
295 return true;
296 }
297
GetImageDataFromAshmem(const std::string & picName,const sptr<Ashmem> & ashmem,int32_t len,std::vector<uint8_t> & value)298 bool FormCacheMgr::GetImageDataFromAshmem(
299 const std::string& picName, const sptr<Ashmem> &ashmem, int32_t len, std::vector<uint8_t> &value)
300 {
301 HILOG_DEBUG("GetImageDataFromAshmem start picName:%{public}s", picName.c_str());
302 if (ashmem == nullptr) {
303 HILOG_ERROR("null ashmem when picName:%{public}s", picName.c_str());
304 return false;
305 }
306
307 bool ret = ashmem->MapReadOnlyAshmem();
308 if (!ret) {
309 HILOG_ERROR("MapReadOnlyAshmem fail, fail reason:%{public}s, picName:%{public}s",
310 strerror(errno), picName.c_str());
311 return false;
312 }
313
314 ScopeGuard stateGuard([ashmem] {
315 if (ashmem) {
316 ashmem->UnmapAshmem();
317 }
318 });
319 const uint8_t* imageData = reinterpret_cast<const uint8_t*>(ashmem->ReadFromAshmem(len, 0));
320 if (imageData == nullptr) {
321 HILOG_ERROR("ReadFromAshmem failed picName:%{public}s", picName.c_str());
322 return false;
323 }
324
325 value = std::vector<uint8_t>(imageData, imageData + len);
326 return true;
327 }
328
DeleteData(const int64_t formId)329 bool FormCacheMgr::DeleteData(const int64_t formId)
330 {
331 HILOG_INFO("formId:%{public}" PRId64, formId);
332 bool isNeedDeleteImgCache = true;
333 nlohmann::json imgCacheObj;
334 {
335 std::lock_guard<std::mutex> lock(cacheMutex_);
336 FormCache formCache;
337 bool ret = GetDataCacheFromDb(formId, formCache);
338 if (!ret) {
339 HILOG_INFO("No DataCache when delete");
340 return true;
341 }
342
343 if (!HasContent(formCache.imgCache)) {
344 HILOG_INFO("Has no imgCache when delete");
345 isNeedDeleteImgCache = false;
346 }
347
348 imgCacheObj = nlohmann::json::parse(formCache.imgCache, nullptr, false);
349 if (imgCacheObj.is_discarded() || !imgCacheObj.is_object()) {
350 HILOG_ERROR("parse data failed");
351 isNeedDeleteImgCache = false;
352 }
353 }
354 if (isNeedDeleteImgCache) {
355 for (auto && [key, value] : imgCacheObj.items()) {
356 DeleteImgCacheInDb(value.dump());
357 }
358 }
359 return DeleteDataCacheInDb(formId);
360 }
361
NeedAcquireProviderData(const int64_t formId) const362 bool FormCacheMgr::NeedAcquireProviderData(const int64_t formId) const
363 {
364 HILOG_DEBUG("NeedAcquireProviderData");
365 FormCache formCache;
366 bool ret = GetDataCacheFromDb(formId, formCache);
367 if (!ret) {
368 HILOG_ERROR("No DataCache");
369 return true;
370 }
371
372 bool hasContent = HasContent(formCache.dataCache) || HasContent(formCache.imgCache);
373 bool isRebootState = formCache.cacheState == CacheState::REBOOT;
374 return !hasContent || isRebootState;
375 }
376
GetDataCacheFromDb(int64_t formId,FormCache & formCache) const377 bool FormCacheMgr::GetDataCacheFromDb(int64_t formId, FormCache &formCache) const
378 {
379 NativeRdb::AbsRdbPredicates absRdbPredicates(FORM_CACHE_TABLE);
380 absRdbPredicates.EqualTo(FORM_ID, std::to_string(formId));
381 auto absSharedResultSet = FormRdbDataMgr::GetInstance().QueryData(absRdbPredicates);
382 if (absSharedResultSet == nullptr) {
383 HILOG_ERROR("GetDataCacheFromDb failed");
384 return false;
385 }
386
387 ScopeGuard stateGuard([absSharedResultSet] {
388 if (absSharedResultSet) {
389 absSharedResultSet->Close();
390 }
391 });
392 if (!absSharedResultSet->HasBlock()) {
393 HILOG_ERROR("absSharedResultSet has no block");
394 return false;
395 }
396
397 int ret = absSharedResultSet->GoToFirstRow();
398 if (ret != NativeRdb::E_OK) {
399 HILOG_ERROR("GoToFirstRow failed, ret:%{public}d", ret);
400 return false;
401 }
402
403 ret = absSharedResultSet->GetString(DATA_CACHE_INDEX, formCache.dataCache);
404 if (ret != NativeRdb::E_OK) {
405 HILOG_DEBUG("GetString dataCache failed, ret:%{public}d", ret);
406 }
407
408 ret = absSharedResultSet->GetString(FORM_IMAGES_INDEX, formCache.imgCache);
409 if (ret != NativeRdb::E_OK) {
410 HILOG_DEBUG("GetString imgCache failed, ret:%{public}d", ret);
411 }
412
413 int32_t cacheState;
414 ret = absSharedResultSet->GetInt(CACHE_STATE_INDEX, cacheState);
415 if (ret != NativeRdb::E_OK) {
416 HILOG_DEBUG("GetInt cacheState failed, ret:%{public}d", ret);
417 }
418 formCache.cacheState = static_cast<CacheState>(cacheState);
419 return true;
420 }
421
SaveDataCacheToDb(int64_t formId,const FormCache & formCache)422 bool FormCacheMgr::SaveDataCacheToDb(int64_t formId, const FormCache &formCache)
423 {
424 NativeRdb::ValuesBucket valuesBucket;
425 valuesBucket.PutString(FORM_ID, std::to_string(formId));
426 valuesBucket.PutString(DATA_CACHE, formCache.dataCache);
427 valuesBucket.PutString(FORM_IMAGES, formCache.imgCache);
428 valuesBucket.PutInt(CACHE_STATE, static_cast<int>(formCache.cacheState));
429 int64_t rowId;
430 bool ret = FormRdbDataMgr::GetInstance().InsertData(FORM_CACHE_TABLE, valuesBucket, rowId);
431 if (!ret) {
432 HILOG_ERROR("SaveDataCacheToDb formId:%{public}s failed.", std::to_string(formId).c_str());
433 return false;
434 }
435 return true;
436 }
437
DeleteDataCacheInDb(int64_t formId)438 bool FormCacheMgr::DeleteDataCacheInDb(int64_t formId)
439 {
440 NativeRdb::AbsRdbPredicates absRdbPredicates(FORM_CACHE_TABLE);
441 absRdbPredicates.EqualTo(FORM_ID, std::to_string(formId));
442 return FormRdbDataMgr::GetInstance().DeleteData(absRdbPredicates);
443 }
444
GetImgCacheFromDb(int64_t rowId,std::vector<uint8_t> & blob,int32_t & size) const445 bool FormCacheMgr::GetImgCacheFromDb(
446 int64_t rowId, std::vector<uint8_t> &blob, int32_t &size) const
447 {
448 NativeRdb::AbsRdbPredicates absRdbPredicates(IMG_CACHE_TABLE);
449 absRdbPredicates.EqualTo(IMAGE_ID, std::to_string(rowId));
450 auto absSharedResultSet = FormRdbDataMgr::GetInstance().QueryData(absRdbPredicates);
451 if (absSharedResultSet == nullptr) {
452 HILOG_ERROR("GetImgCacheFromDb failed");
453 return false;
454 }
455
456 ScopeGuard stateGuard([absSharedResultSet] {
457 if (absSharedResultSet) {
458 absSharedResultSet->Close();
459 }
460 });
461 if (!absSharedResultSet->HasBlock()) {
462 HILOG_ERROR("absSharedResultSet has no block");
463 return false;
464 }
465
466 int ret = absSharedResultSet->GoToFirstRow();
467 if (ret != NativeRdb::E_OK) {
468 HILOG_ERROR("GoToFirstRow failed,ret:%{public}d", ret);
469 return false;
470 }
471
472 ret = absSharedResultSet->GetBlob(IMAGE_BIT_INDEX, blob);
473 if (ret != NativeRdb::E_OK) {
474 HILOG_ERROR("GetBlob failed, ret:%{public}d", ret);
475 return false;
476 }
477
478 ret = absSharedResultSet->GetInt(IMAGE_SIZE_INDEX, size);
479 if (ret != NativeRdb::E_OK) {
480 HILOG_ERROR("GetInt size failed, ret:%{public}d", ret);
481 return false;
482 }
483
484 return true;
485 }
486
SaveImgCacheToDb(const std::vector<uint8_t> & value,int32_t size,int64_t & rowId)487 bool FormCacheMgr::SaveImgCacheToDb(const std::vector<uint8_t> &value, int32_t size, int64_t &rowId)
488 {
489 NativeRdb::ValuesBucket valuesBucket;
490 valuesBucket.PutBlob(IMAGE_BIT, value);
491 valuesBucket.PutInt(IMAGE_SIZE, size);
492 bool ret = FormRdbDataMgr::GetInstance().InsertData(IMG_CACHE_TABLE, valuesBucket, rowId);
493 if (!ret) {
494 HILOG_ERROR("SaveImgCacheToDb failed");
495 return false;
496 }
497 return true;
498 }
499
DeleteImgCacheInDb(const std::string & rowId)500 bool FormCacheMgr::DeleteImgCacheInDb(const std::string &rowId)
501 {
502 if (rowId.empty()) {
503 return false;
504 }
505
506 NativeRdb::AbsRdbPredicates absRdbPredicates(IMG_CACHE_TABLE);
507 absRdbPredicates.EqualTo(IMAGE_ID, rowId);
508 return FormRdbDataMgr::GetInstance().DeleteData(absRdbPredicates);
509 }
510
ResetCacheStateAfterReboot()511 void FormCacheMgr::ResetCacheStateAfterReboot()
512 {
513 std::string sql = "UPDATE " + FORM_CACHE_TABLE + " SET " + CACHE_STATE + " = 1;";
514 FormRdbDataMgr::GetInstance().ExecuteSql(sql);
515 }
516 } // namespace AppExecFwk
517 } // namespace OHOS
518