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 if (blob.size() <= 0) {
147 HILOG_ERROR("GetImgCacheFromDb failed due to blob is empty.");
148 return false;
149 }
150
151 sptr<FormAshmem> formAshmem = new (std::nothrow) FormAshmem();
152 if (formAshmem == nullptr) {
153 HILOG_ERROR("Alloc ashmem failed");
154 return false;
155 }
156
157 if (!formAshmem->WriteToAshmem(key, reinterpret_cast<char *>(blob.data()),
158 static_cast<int32_t>(blob.size()))) {
159 HILOG_ERROR("Write to ashmem failed");
160 return false;
161 }
162
163 imageDataMap[key] = std::make_pair(formAshmem, size);
164 }
165
166 return true;
167 }
168
AddData(int64_t formId,const FormProviderData & formProviderData)169 bool FormCacheMgr::AddData(int64_t formId, const FormProviderData &formProviderData)
170 {
171 HILOG_INFO("AddData start, formId:%{public}" PRId64 "", formId);
172 std::lock_guard<std::mutex> lock(cacheMutex_);
173
174 FormCache formCache;
175 formCache.formId = formId;
176 GetDataCacheFromDb(formId, formCache);
177 if (!AddImgData(formProviderData, formCache)) {
178 HILOG_ERROR("AddImgData failed.");
179 return false;
180 }
181
182 if (!AddCacheData(formProviderData, formCache)) {
183 HILOG_ERROR("AddCacheData failed.");
184 return false;
185 }
186
187 // Save dataCache and imgCache
188 formCache.cacheState = CacheState::DEFAULT;
189 return SaveDataCacheToDb(formId, formCache);
190 }
191
AddImgData(const FormProviderData & formProviderData,FormCache & formCache)192 bool FormCacheMgr::AddImgData(
193 const FormProviderData &formProviderData, FormCache &formCache)
194 {
195 nlohmann::json newImgDbData;
196 if (!AddImgDataToDb(formProviderData, newImgDbData)) {
197 HILOG_ERROR("AddImgDataToDb failed.");
198 return false;
199 }
200
201 if (newImgDbData.empty()) {
202 HILOG_INFO("No new imgData.");
203 return true;
204 }
205
206 if (!HasContent(formCache.imgCache)) {
207 // No imgCache in db
208 formCache.imgCache = newImgDbData.dump();
209 return true;
210 }
211
212 nlohmann::json imgCacheObj = nlohmann::json::parse(formCache.imgCache, nullptr, false);
213 if (imgCacheObj.is_discarded() || !imgCacheObj.is_object()) {
214 HILOG_ERROR("failed to parse data.");
215 return false;
216 }
217
218 // Update imgCache
219 for (auto && [key, value] : newImgDbData.items()) {
220 if (imgCacheObj.find(key) != imgCacheObj.end()) {
221 DeleteImgCacheInDb(imgCacheObj[key].dump());
222 }
223
224 imgCacheObj[key] = value;
225 }
226
227 formCache.imgCache = imgCacheObj.dump();
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("failed to parse data.");
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("failed to parse data.");
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("failed to 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("failed to 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("ashmem is null 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("DeleteData start, formId:%{public}" PRId64" ", formId);
332 std::lock_guard<std::mutex> lock(cacheMutex_);
333 FormCache formCache;
334 bool ret = GetDataCacheFromDb(formId, formCache);
335 if (!ret) {
336 HILOG_INFO("No DataCache when delete.");
337 return true;
338 }
339
340 InnerDeleteImageData(formCache);
341 return DeleteDataCacheInDb(formId);
342 }
343
NeedAcquireProviderData(const int64_t formId) const344 bool FormCacheMgr::NeedAcquireProviderData(const int64_t formId) const
345 {
346 HILOG_DEBUG("NeedAcquireProviderData");
347 FormCache formCache;
348 bool ret = GetDataCacheFromDb(formId, formCache);
349 if (!ret) {
350 HILOG_ERROR("No DataCache.");
351 return true;
352 }
353
354 bool hasContent = HasContent(formCache.dataCache) || HasContent(formCache.imgCache);
355 bool isRebootState = formCache.cacheState == CacheState::REBOOT;
356 return !hasContent || isRebootState;
357 }
358
GetDataCacheFromDb(int64_t formId,FormCache & formCache) const359 bool FormCacheMgr::GetDataCacheFromDb(int64_t formId, FormCache &formCache) const
360 {
361 NativeRdb::AbsRdbPredicates absRdbPredicates(FORM_CACHE_TABLE);
362 absRdbPredicates.EqualTo(FORM_ID, std::to_string(formId));
363 auto absSharedResultSet = rdbDataManager_->QueryData(absRdbPredicates);
364 if (absSharedResultSet == nullptr) {
365 HILOG_ERROR("GetDataCacheFromDb failed.");
366 return false;
367 }
368
369 ScopeGuard stateGuard([absSharedResultSet] {
370 if (absSharedResultSet) {
371 absSharedResultSet->Close();
372 }
373 });
374 if (!absSharedResultSet->HasBlock()) {
375 HILOG_ERROR("absSharedResultSet has no block");
376 return false;
377 }
378
379 int ret = absSharedResultSet->GoToFirstRow();
380 if (ret != NativeRdb::E_OK) {
381 HILOG_ERROR("GoToFirstRow failed, ret: %{public}d", ret);
382 return false;
383 }
384
385 ret = absSharedResultSet->GetString(DATA_CACHE_INDEX, formCache.dataCache);
386 if (ret != NativeRdb::E_OK) {
387 HILOG_DEBUG("GetString dataCache failed, ret: %{public}d", ret);
388 }
389
390 ret = absSharedResultSet->GetString(FORM_IMAGES_INDEX, formCache.imgCache);
391 if (ret != NativeRdb::E_OK) {
392 HILOG_DEBUG("GetString imgCache failed, ret: %{public}d", ret);
393 }
394
395 int32_t cacheState;
396 ret = absSharedResultSet->GetInt(CACHE_STATE_INDEX, cacheState);
397 if (ret != NativeRdb::E_OK) {
398 HILOG_DEBUG("GetInt cacheState failed, ret: %{public}d", ret);
399 }
400 formCache.cacheState = static_cast<CacheState>(cacheState);
401 return true;
402 }
403
SaveDataCacheToDb(int64_t formId,const FormCache & formCache)404 bool FormCacheMgr::SaveDataCacheToDb(int64_t formId, const FormCache &formCache)
405 {
406 NativeRdb::ValuesBucket valuesBucket;
407 valuesBucket.PutString(FORM_ID, std::to_string(formId));
408 valuesBucket.PutString(DATA_CACHE, formCache.dataCache);
409 valuesBucket.PutString(FORM_IMAGES, formCache.imgCache);
410 valuesBucket.PutInt(CACHE_STATE, static_cast<int>(formCache.cacheState));
411 int64_t rowId;
412 bool ret = rdbDataManager_->InsertData(FORM_CACHE_TABLE, valuesBucket, rowId);
413 if (!ret) {
414 HILOG_ERROR("SaveDataCacheToDb formId:%{public}s failed.", std::to_string(formId).c_str());
415 return false;
416 }
417 return true;
418 }
419
InnerDeleteImageData(const FormCache & formCache)420 bool FormCacheMgr::InnerDeleteImageData(const FormCache &formCache)
421 {
422 if (!HasContent(formCache.imgCache)) {
423 HILOG_INFO("Has no imgCache when delete.");
424 return true;
425 }
426
427 nlohmann::json imgCacheObj = nlohmann::json::parse(formCache.imgCache, nullptr, false);
428 if (imgCacheObj.is_discarded() || !imgCacheObj.is_object()) {
429 HILOG_ERROR("failed to parse data.");
430 return false;
431 }
432
433 for (auto && [key, value] : imgCacheObj.items()) {
434 DeleteImgCacheInDb(value.dump());
435 }
436
437 return true;
438 }
439
DeleteDataCacheInDb(int64_t formId)440 bool FormCacheMgr::DeleteDataCacheInDb(int64_t formId)
441 {
442 NativeRdb::AbsRdbPredicates absRdbPredicates(FORM_CACHE_TABLE);
443 absRdbPredicates.EqualTo(FORM_ID, std::to_string(formId));
444 return rdbDataManager_->DeleteData(absRdbPredicates);
445 }
446
GetImgCacheFromDb(int64_t rowId,std::vector<uint8_t> & blob,int32_t & size) const447 bool FormCacheMgr::GetImgCacheFromDb(
448 int64_t rowId, std::vector<uint8_t> &blob, int32_t &size) const
449 {
450 NativeRdb::AbsRdbPredicates absRdbPredicates(IMG_CACHE_TABLE);
451 absRdbPredicates.EqualTo(IMAGE_ID, std::to_string(rowId));
452 auto absSharedResultSet = rdbDataManager_->QueryData(absRdbPredicates);
453 if (absSharedResultSet == nullptr) {
454 HILOG_ERROR("GetImgCacheFromDb failed.");
455 return false;
456 }
457
458 ScopeGuard stateGuard([absSharedResultSet] {
459 if (absSharedResultSet) {
460 absSharedResultSet->Close();
461 }
462 });
463 if (!absSharedResultSet->HasBlock()) {
464 HILOG_ERROR("absSharedResultSet has no block");
465 return false;
466 }
467
468 int ret = absSharedResultSet->GoToFirstRow();
469 if (ret != NativeRdb::E_OK) {
470 HILOG_ERROR("GoToFirstRow failed, ret: %{public}d", ret);
471 return false;
472 }
473
474 ret = absSharedResultSet->GetBlob(IMAGE_BIT_INDEX, blob);
475 if (ret != NativeRdb::E_OK) {
476 HILOG_ERROR("GetBlob failed, ret: %{public}d", ret);
477 return false;
478 }
479
480 ret = absSharedResultSet->GetInt(IMAGE_SIZE_INDEX, size);
481 if (ret != NativeRdb::E_OK) {
482 HILOG_ERROR("GetInt size failed, ret: %{public}d", ret);
483 return false;
484 }
485
486 return true;
487 }
488
SaveImgCacheToDb(const std::vector<uint8_t> & value,int32_t size,int64_t & rowId)489 bool FormCacheMgr::SaveImgCacheToDb(const std::vector<uint8_t> &value, int32_t size, int64_t &rowId)
490 {
491 NativeRdb::ValuesBucket valuesBucket;
492 valuesBucket.PutBlob(IMAGE_BIT, value);
493 valuesBucket.PutInt(IMAGE_SIZE, size);
494 bool ret = rdbDataManager_->InsertData(IMG_CACHE_TABLE, valuesBucket, rowId);
495 if (!ret) {
496 HILOG_ERROR("SaveImgCacheToDb failed.");
497 return false;
498 }
499 return true;
500 }
501
DeleteImgCacheInDb(const std::string & rowId)502 bool FormCacheMgr::DeleteImgCacheInDb(const std::string &rowId)
503 {
504 if (rowId.empty()) {
505 return false;
506 }
507
508 NativeRdb::AbsRdbPredicates absRdbPredicates(IMG_CACHE_TABLE);
509 absRdbPredicates.EqualTo(IMAGE_ID, rowId);
510 return rdbDataManager_->DeleteData(absRdbPredicates);
511 }
512
ResetCacheStateAfterReboot()513 void FormCacheMgr::ResetCacheStateAfterReboot()
514 {
515 std::string sql = "UPDATE " + FORM_CACHE_TABLE + " SET " + CACHE_STATE + " = 1;";
516 rdbDataManager_->ExecuteSql(sql);
517 }
518 } // namespace AppExecFwk
519 } // namespace OHOS
520