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 std::lock_guard<std::mutex> lock(cacheMutex_);
98 FormCache formCache;
99 formCache.formId = formId;
100 bool ret = GetDataCacheFromDb(formId, formCache);
101 if (!ret) {
102 HILOG_ERROR("no data in db");
103 return false;
104 }
105
106 bool hasContent = false;
107 if (HasContent(formCache.dataCache)) {
108 nlohmann::json dataCacheObj = nlohmann::json::parse(formCache.dataCache, nullptr, false);
109 if (dataCacheObj.is_discarded() || !dataCacheObj.is_object()) {
110 HILOG_ERROR("GetData failed due to dataCache is discarded");
111 return false;
112 }
113
114 data = formCache.dataCache;
115 hasContent = true;
116 }
117
118 if (HasContent(formCache.imgCache)) {
119 ret = InnerGetImageData(formCache, imageDataMap);
120 if (!ret) {
121 HILOG_ERROR("InnerGetImageData failed");
122 return false;
123 }
124
125 hasContent = true;
126 }
127
128 return hasContent;
129 }
130
InnerGetImageData( const FormCache &formCache, std::map<std::string, std::pair<sptr<FormAshmem>, int32_t>> &imageDataMap) const131 bool FormCacheMgr::InnerGetImageData(
132 const FormCache &formCache,
133 std::map<std::string, std::pair<sptr<FormAshmem>, int32_t>> &imageDataMap) const
134 {
135 HILOG_DEBUG("InnerGetImageData start");
136 nlohmann::json imgCacheObj = nlohmann::json::parse(formCache.imgCache, nullptr, false);
137 if (imgCacheObj.is_discarded() || !imgCacheObj.is_object()) {
138 HILOG_ERROR("imgCacheObj is discarded");
139 return false;
140 }
141
142 for (auto && [key, value] : imgCacheObj.items()) {
143 int64_t rowId;
144 std::stringstream ss;
145 ss << value.dump();
146 ss >> rowId;
147 std::vector<uint8_t> blob;
148 int32_t size = 0;
149 if (!GetImgCacheFromDb(rowId, blob, size)) {
150 HILOG_ERROR("GetImgCacheFromDb failed");
151 return false;
152 }
153
154 if (blob.size() <= 0) {
155 HILOG_ERROR("GetImgCacheFromDb failed due to blob is empty");
156 return false;
157 }
158
159 sptr<FormAshmem> formAshmem = new (std::nothrow) FormAshmem();
160 if (formAshmem == nullptr) {
161 HILOG_ERROR("Alloc ashmem failed");
162 return false;
163 }
164
165 if (!formAshmem->WriteToAshmem(key, reinterpret_cast<char *>(blob.data()),
166 static_cast<int32_t>(blob.size()))) {
167 HILOG_ERROR("Write to ashmem failed");
168 return false;
169 }
170
171 imageDataMap[key] = std::make_pair(formAshmem, size);
172 }
173
174 return true;
175 }
176
AddData(int64_t formId, const FormProviderData &formProviderData)177 bool FormCacheMgr::AddData(int64_t formId, const FormProviderData &formProviderData)
178 {
179 HILOG_INFO("formId:%{public}" PRId64, formId);
180 std::lock_guard<std::mutex> lock(cacheMutex_);
181
182 FormCache formCache;
183 formCache.formId = formId;
184 GetDataCacheFromDb(formId, formCache);
185 if (!AddImgData(formProviderData, formCache)) {
186 HILOG_ERROR("AddImgData failed");
187 return false;
188 }
189
190 if (!AddCacheData(formProviderData, formCache)) {
191 HILOG_ERROR("AddCacheData failed");
192 return false;
193 }
194
195 // Save dataCache and imgCache
196 formCache.cacheState = CacheState::DEFAULT;
197 FormReport::GetInstance().SetDurationEndTime(formId, FormUtil::GetCurrentSteadyClockMillseconds());
198 return SaveDataCacheToDb(formId, formCache);
199 }
200
AddImgData( const FormProviderData &formProviderData, FormCache &formCache)201 bool FormCacheMgr::AddImgData(
202 const FormProviderData &formProviderData, FormCache &formCache)
203 {
204 nlohmann::json newImgDbData;
205 if (!AddImgDataToDb(formProviderData, newImgDbData)) {
206 HILOG_ERROR("AddImgDataToDb failed");
207 return false;
208 }
209
210 if (newImgDbData.empty()) {
211 HILOG_INFO("No new imgData");
212 return true;
213 }
214
215 if (HasContent(formCache.imgCache)) {
216 nlohmann::json imgCacheObj = nlohmann::json::parse(formCache.imgCache, nullptr, false);
217 if (imgCacheObj.is_discarded() || !imgCacheObj.is_object()) {
218 HILOG_ERROR("parse data failed");
219 return false;
220 }
221 // delete old images
222 for (auto && [key, value] : imgCacheObj.items()) {
223 DeleteImgCacheInDb(imgCacheObj[key].dump());
224 }
225 }
226
227 formCache.imgCache = newImgDbData.dump();
228
229 return true;
230 }
231
AddCacheData( const FormProviderData &formProviderData, FormCache &formCache)232 bool FormCacheMgr::AddCacheData(
233 const FormProviderData &formProviderData, FormCache &formCache)
234 {
235 auto newDataStr = formProviderData.GetDataString();
236 nlohmann::json newDataObj;
237 if (HasContent(newDataStr)) {
238 newDataObj = nlohmann::json::parse(newDataStr, nullptr, false);
239 if (newDataObj.is_discarded() || !newDataObj.is_object()) {
240 HILOG_ERROR("parse data failed");
241 return false;
242 }
243
244 newDataObj.erase("formImages");
245 }
246
247 if (newDataObj.empty()) {
248 HILOG_INFO("No new cacheData");
249 return true;
250 }
251
252 if (!HasContent(formCache.dataCache)) {
253 // No dataCache in db
254 formCache.dataCache = newDataObj.dump();
255 return true;
256 }
257
258 nlohmann::json dataCacheObj = nlohmann::json::parse(formCache.dataCache, nullptr, false);
259 if (dataCacheObj.is_discarded() || !dataCacheObj.is_object()) {
260 HILOG_ERROR("parse data failed");
261 return false;
262 }
263
264 // Update dataCache
265 for (auto && [key, value] : newDataObj.items()) {
266 dataCacheObj[key] = value;
267 }
268 formCache.dataCache = dataCacheObj.dump();
269 return true;
270 }
271
AddImgDataToDb( const FormProviderData &formProviderData, nlohmann::json &imgDataJson)272 bool FormCacheMgr::AddImgDataToDb(
273 const FormProviderData &formProviderData, nlohmann::json &imgDataJson)
274 {
275 auto imgCache = formProviderData.GetImageDataMap();
276 HILOG_DEBUG("AddImgDataToDb imgCache size:%{public}zu", imgCache.size());
277 for (const auto &iter : imgCache) {
278 int64_t rowId = INVALID_INDEX;
279 std::vector<uint8_t> value;
280 bool ret = GetImageDataFromAshmem(
281 iter.first, iter.second.first->GetAshmem(), iter.second.first->GetAshmemSize(), value);
282 if (!ret) {
283 HILOG_ERROR("fail get img data imgName:%{public}s", iter.first.c_str());
284 return false;
285 }
286
287 ret = SaveImgCacheToDb(value, iter.second.second, rowId);
288 if (!ret || rowId == INVALID_INDEX) {
289 HILOG_ERROR("fail save img data imgName:%{public}s", iter.first.c_str());
290 return false;
291 }
292
293 imgDataJson[iter.first] = rowId;
294 }
295
296 return true;
297 }
298
GetImageDataFromAshmem( const std::string& picName, const sptr<Ashmem> &ashmem, int32_t len, std::vector<uint8_t> &value)299 bool FormCacheMgr::GetImageDataFromAshmem(
300 const std::string& picName, const sptr<Ashmem> &ashmem, int32_t len, std::vector<uint8_t> &value)
301 {
302 HILOG_DEBUG("GetImageDataFromAshmem start picName:%{public}s", picName.c_str());
303 if (ashmem == nullptr) {
304 HILOG_ERROR("null ashmem when picName:%{public}s", picName.c_str());
305 return false;
306 }
307
308 bool ret = ashmem->MapReadOnlyAshmem();
309 if (!ret) {
310 HILOG_ERROR("MapReadOnlyAshmem fail, fail reason:%{public}s, picName:%{public}s",
311 strerror(errno), picName.c_str());
312 return false;
313 }
314
315 ScopeGuard stateGuard([ashmem] {
316 if (ashmem) {
317 ashmem->UnmapAshmem();
318 }
319 });
320 const uint8_t* imageData = reinterpret_cast<const uint8_t*>(ashmem->ReadFromAshmem(len, 0));
321 if (imageData == nullptr) {
322 HILOG_ERROR("ReadFromAshmem failed picName:%{public}s", picName.c_str());
323 return false;
324 }
325
326 value = std::vector<uint8_t>(imageData, imageData + len);
327 return true;
328 }
329
DeleteData(const int64_t formId)330 bool FormCacheMgr::DeleteData(const int64_t formId)
331 {
332 HILOG_INFO("formId:%{public}" PRId64, formId);
333 std::lock_guard<std::mutex> lock(cacheMutex_);
334 FormCache formCache;
335 bool ret = GetDataCacheFromDb(formId, formCache);
336 if (!ret) {
337 HILOG_INFO("No DataCache when delete");
338 return true;
339 }
340
341 InnerDeleteImageData(formCache);
342 return DeleteDataCacheInDb(formId);
343 }
344
NeedAcquireProviderData(const int64_t formId) const345 bool FormCacheMgr::NeedAcquireProviderData(const int64_t formId) const
346 {
347 HILOG_DEBUG("NeedAcquireProviderData");
348 FormCache formCache;
349 bool ret = GetDataCacheFromDb(formId, formCache);
350 if (!ret) {
351 HILOG_ERROR("No DataCache");
352 return true;
353 }
354
355 bool hasContent = HasContent(formCache.dataCache) || HasContent(formCache.imgCache);
356 bool isRebootState = formCache.cacheState == CacheState::REBOOT;
357 return !hasContent || isRebootState;
358 }
359
GetDataCacheFromDb(int64_t formId, FormCache &formCache) const360 bool FormCacheMgr::GetDataCacheFromDb(int64_t formId, FormCache &formCache) const
361 {
362 NativeRdb::AbsRdbPredicates absRdbPredicates(FORM_CACHE_TABLE);
363 absRdbPredicates.EqualTo(FORM_ID, std::to_string(formId));
364 auto absSharedResultSet = FormRdbDataMgr::GetInstance().QueryData(absRdbPredicates);
365 if (absSharedResultSet == nullptr) {
366 HILOG_ERROR("GetDataCacheFromDb failed");
367 return false;
368 }
369
370 ScopeGuard stateGuard([absSharedResultSet] {
371 if (absSharedResultSet) {
372 absSharedResultSet->Close();
373 }
374 });
375 if (!absSharedResultSet->HasBlock()) {
376 HILOG_ERROR("absSharedResultSet has no block");
377 return false;
378 }
379
380 int ret = absSharedResultSet->GoToFirstRow();
381 if (ret != NativeRdb::E_OK) {
382 HILOG_ERROR("GoToFirstRow failed, ret:%{public}d", ret);
383 return false;
384 }
385
386 ret = absSharedResultSet->GetString(DATA_CACHE_INDEX, formCache.dataCache);
387 if (ret != NativeRdb::E_OK) {
388 HILOG_DEBUG("GetString dataCache failed, ret:%{public}d", ret);
389 }
390
391 ret = absSharedResultSet->GetString(FORM_IMAGES_INDEX, formCache.imgCache);
392 if (ret != NativeRdb::E_OK) {
393 HILOG_DEBUG("GetString imgCache failed, ret:%{public}d", ret);
394 }
395
396 int32_t cacheState;
397 ret = absSharedResultSet->GetInt(CACHE_STATE_INDEX, cacheState);
398 if (ret != NativeRdb::E_OK) {
399 HILOG_DEBUG("GetInt cacheState failed, ret:%{public}d", ret);
400 }
401 formCache.cacheState = static_cast<CacheState>(cacheState);
402 return true;
403 }
404
SaveDataCacheToDb(int64_t formId, const FormCache &formCache)405 bool FormCacheMgr::SaveDataCacheToDb(int64_t formId, const FormCache &formCache)
406 {
407 NativeRdb::ValuesBucket valuesBucket;
408 valuesBucket.PutString(FORM_ID, std::to_string(formId));
409 valuesBucket.PutString(DATA_CACHE, formCache.dataCache);
410 valuesBucket.PutString(FORM_IMAGES, formCache.imgCache);
411 valuesBucket.PutInt(CACHE_STATE, static_cast<int>(formCache.cacheState));
412 int64_t rowId;
413 bool ret = FormRdbDataMgr::GetInstance().InsertData(FORM_CACHE_TABLE, valuesBucket, rowId);
414 if (!ret) {
415 HILOG_ERROR("SaveDataCacheToDb formId:%{public}s failed.", std::to_string(formId).c_str());
416 return false;
417 }
418 return true;
419 }
420
InnerDeleteImageData(const FormCache &formCache)421 bool FormCacheMgr::InnerDeleteImageData(const FormCache &formCache)
422 {
423 if (!HasContent(formCache.imgCache)) {
424 HILOG_INFO("Has no imgCache when delete");
425 return true;
426 }
427
428 nlohmann::json imgCacheObj = nlohmann::json::parse(formCache.imgCache, nullptr, false);
429 if (imgCacheObj.is_discarded() || !imgCacheObj.is_object()) {
430 HILOG_ERROR("parse data failed");
431 return false;
432 }
433
434 for (auto && [key, value] : imgCacheObj.items()) {
435 DeleteImgCacheInDb(value.dump());
436 }
437
438 return true;
439 }
440
DeleteDataCacheInDb(int64_t formId)441 bool FormCacheMgr::DeleteDataCacheInDb(int64_t formId)
442 {
443 NativeRdb::AbsRdbPredicates absRdbPredicates(FORM_CACHE_TABLE);
444 absRdbPredicates.EqualTo(FORM_ID, std::to_string(formId));
445 return FormRdbDataMgr::GetInstance().DeleteData(absRdbPredicates);
446 }
447
GetImgCacheFromDb( int64_t rowId, std::vector<uint8_t> &blob, int32_t &size) const448 bool FormCacheMgr::GetImgCacheFromDb(
449 int64_t rowId, std::vector<uint8_t> &blob, int32_t &size) const
450 {
451 NativeRdb::AbsRdbPredicates absRdbPredicates(IMG_CACHE_TABLE);
452 absRdbPredicates.EqualTo(IMAGE_ID, std::to_string(rowId));
453 auto absSharedResultSet = FormRdbDataMgr::GetInstance().QueryData(absRdbPredicates);
454 if (absSharedResultSet == nullptr) {
455 HILOG_ERROR("GetImgCacheFromDb failed");
456 return false;
457 }
458
459 ScopeGuard stateGuard([absSharedResultSet] {
460 if (absSharedResultSet) {
461 absSharedResultSet->Close();
462 }
463 });
464 if (!absSharedResultSet->HasBlock()) {
465 HILOG_ERROR("absSharedResultSet has no block");
466 return false;
467 }
468
469 int ret = absSharedResultSet->GoToFirstRow();
470 if (ret != NativeRdb::E_OK) {
471 HILOG_ERROR("GoToFirstRow failed,ret:%{public}d", ret);
472 return false;
473 }
474
475 ret = absSharedResultSet->GetBlob(IMAGE_BIT_INDEX, blob);
476 if (ret != NativeRdb::E_OK) {
477 HILOG_ERROR("GetBlob failed, ret:%{public}d", ret);
478 return false;
479 }
480
481 ret = absSharedResultSet->GetInt(IMAGE_SIZE_INDEX, size);
482 if (ret != NativeRdb::E_OK) {
483 HILOG_ERROR("GetInt size failed, ret:%{public}d", ret);
484 return false;
485 }
486
487 return true;
488 }
489
SaveImgCacheToDb(const std::vector<uint8_t> &value, int32_t size, int64_t &rowId)490 bool FormCacheMgr::SaveImgCacheToDb(const std::vector<uint8_t> &value, int32_t size, int64_t &rowId)
491 {
492 NativeRdb::ValuesBucket valuesBucket;
493 valuesBucket.PutBlob(IMAGE_BIT, value);
494 valuesBucket.PutInt(IMAGE_SIZE, size);
495 bool ret = FormRdbDataMgr::GetInstance().InsertData(IMG_CACHE_TABLE, valuesBucket, rowId);
496 if (!ret) {
497 HILOG_ERROR("SaveImgCacheToDb failed");
498 return false;
499 }
500 return true;
501 }
502
DeleteImgCacheInDb(const std::string &rowId)503 bool FormCacheMgr::DeleteImgCacheInDb(const std::string &rowId)
504 {
505 if (rowId.empty()) {
506 return false;
507 }
508
509 NativeRdb::AbsRdbPredicates absRdbPredicates(IMG_CACHE_TABLE);
510 absRdbPredicates.EqualTo(IMAGE_ID, rowId);
511 return FormRdbDataMgr::GetInstance().DeleteData(absRdbPredicates);
512 }
513
ResetCacheStateAfterReboot()514 void FormCacheMgr::ResetCacheStateAfterReboot()
515 {
516 std::string sql = "UPDATE " + FORM_CACHE_TABLE + " SET " + CACHE_STATE + " = 1;";
517 FormRdbDataMgr::GetInstance().ExecuteSql(sql);
518 }
519 } // namespace AppExecFwk
520 } // namespace OHOS
521