1 /*
2 * Copyright (c) 2021 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_storage_mgr.h"
17
18 #include <cinttypes>
19 #include <dirent.h>
20 #include <fstream>
21 #include <iomanip>
22 #include <stdio.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include "form_storage_mgr.h"
28 #include "hilog_wrapper.h"
29 #include "kvstore_death_recipient_callback.h"
30 #include "securec.h"
31 #include "string_ex.h"
32 #include "types.h"
33
34 namespace OHOS {
35 namespace AppExecFwk {
36 namespace {
37 const int32_t MAX_TIMES = 600; // 1min
38 const int32_t SLEEP_INTERVAL = 100 * 1000; // 100ms
39 } // namespace
40
FormStorageMgr()41 FormStorageMgr::FormStorageMgr()
42 {
43 HILOG_INFO("instance:%{private}p is created", this);
44 TryTwice([this] { return GetKvStore(); });
45 RegisterKvStoreDeathListener();
46 }
47
~FormStorageMgr()48 FormStorageMgr::~FormStorageMgr()
49 {
50 HILOG_INFO("instance:%{private}p is destroyed", this);
51 dataManager_.CloseKvStore(appId_, kvStorePtr_);
52 }
53
SaveEntries(const std::vector<DistributedKv::Entry> & allEntries,std::vector<InnerFormInfo> & innerFormInfos)54 void FormStorageMgr::SaveEntries(
55 const std::vector<DistributedKv::Entry> &allEntries, std::vector<InnerFormInfo> &innerFormInfos)
56 {
57 for (const auto &item : allEntries) {
58 std::string formId;
59 InnerFormInfo innerFormInfo;
60
61 nlohmann::json jsonObject = nlohmann::json::parse(item.value.ToString(), nullptr, false);
62 if (jsonObject.is_discarded()) {
63 HILOG_ERROR("error key: %{private}s", item.key.ToString().c_str());
64 // it's an bad json, delete it
65 {
66 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
67 kvStorePtr_->Delete(item.key);
68 }
69 continue;
70 }
71 if (innerFormInfo.FromJson(jsonObject) != true) {
72 HILOG_ERROR("error key: %{private}s", item.key.ToString().c_str());
73 // it's an error value, delete it
74 {
75 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
76 kvStorePtr_->Delete(item.key);
77 }
78 continue;
79 }
80
81 if (std::find(innerFormInfos.begin(), innerFormInfos.end(), innerFormInfo) == innerFormInfos.end()) {
82 HILOG_DEBUG("emplace FormInfos: %{public}s", formId.c_str());
83 std::map<std::string, InnerFormInfo> allDevicesInfos;
84 allDevicesInfos.emplace(formId, innerFormInfo);
85 innerFormInfos.emplace_back(innerFormInfo);
86 }
87 }
88 HILOG_DEBUG("SaveEntries end");
89 }
90
91 /**
92 * @brief Load all form data from DB to innerFormInfos.
93 * @param innerFormInfos Storage all form data.
94 * @return Returns ERR_OK on success, others on failure.
95 */
LoadFormData(std::vector<InnerFormInfo> & innerFormInfos)96 ErrCode FormStorageMgr::LoadFormData(std::vector<InnerFormInfo> &innerFormInfos)
97 {
98 HILOG_INFO("%{public}s called.", __func__);
99 bool ret = ERR_OK;
100 {
101 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
102 if (!CheckKvStore()) {
103 HILOG_ERROR("kvStore is nullptr");
104 return ERR_APPEXECFWK_FORM_COMMON_CODE;
105 }
106 }
107 DistributedKv::Status status;
108 std::vector<DistributedKv::Entry> allEntries;
109 TryTwice([this, &status, &allEntries] {
110 status = GetEntries(allEntries);
111 return status;
112 });
113
114 if (status != DistributedKv::Status::SUCCESS) {
115 HILOG_ERROR("get entries error: %{public}d", status);
116 ret = ERR_APPEXECFWK_FORM_COMMON_CODE;
117 } else {
118 SaveEntries(allEntries, innerFormInfos);
119 }
120
121 HILOG_INFO("%{public}s, readdir over", __func__);
122 return ret;
123 }
124
125 /**
126 * @brief Get form data from DB to innerFormInfo with formId.
127 * @param innerFormInfo Storage form data.
128 * @return Returns ERR_OK on success, others on failure.
129 */
GetStorageFormInfoById(const std::string & formId,InnerFormInfo & innerFormInfo)130 ErrCode FormStorageMgr::GetStorageFormInfoById(const std::string &formId, InnerFormInfo &innerFormInfo)
131 {
132 ErrCode ret = ERR_OK;
133 HILOG_DEBUG("%{public}s called, formId[%{public}s]", __func__, formId.c_str());
134
135 {
136 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
137 if (!CheckKvStore()) {
138 HILOG_ERROR("kvStore is nullptr");
139 return ERR_APPEXECFWK_FORM_COMMON_CODE;
140 }
141 }
142
143 DistributedKv::Status status = DistributedKv::Status::ERROR;
144 std::vector<DistributedKv::Entry> allEntries;
145 DistributedKv::Key key(formId);
146 if (kvStorePtr_) {
147 // sync call GetEntries, the callback will be trigger at once
148 status = kvStorePtr_->GetEntries(key, allEntries);
149 }
150
151 if (status != DistributedKv::Status::SUCCESS) {
152 HILOG_ERROR("get entries error: %{public}d", status);
153 ret = ERR_APPEXECFWK_FORM_COMMON_CODE;
154 } else {
155 if (allEntries.empty()) {
156 HILOG_ERROR("%{public}s not match any FormInfo", formId.c_str());
157 ret = ERR_APPEXECFWK_FORM_COMMON_CODE;
158 } else {
159 nlohmann::json jsonObject = nlohmann::json::parse(allEntries.front().value.ToString(), nullptr, false);
160 if (jsonObject.is_discarded()) {
161 HILOG_ERROR("error key: %{private}s", allEntries.front().key.ToString().c_str());
162 ret = ERR_APPEXECFWK_FORM_COMMON_CODE;
163 }
164 if (innerFormInfo.FromJson(jsonObject) != true) {
165 HILOG_ERROR("error key: %{private}s", allEntries.front().key.ToString().c_str());
166 ret = ERR_APPEXECFWK_FORM_COMMON_CODE;
167 }
168 }
169 }
170
171 return ret;
172 }
173
174 /**
175 * @brief Save or update the form data in DB.
176 * @param innerFormInfo Indicates the InnerFormInfo object to be save.
177 * @return Returns ERR_OK on success, others on failure.
178 */
SaveStorageFormInfo(const InnerFormInfo & innerFormInfo)179 ErrCode FormStorageMgr::SaveStorageFormInfo(const InnerFormInfo &innerFormInfo)
180 {
181 HILOG_INFO("%{public}s called, formId[%{public}" PRId64 "]", __func__, innerFormInfo.GetFormId());
182 ErrCode ret = ERR_OK;
183 std::string formId = std::to_string(innerFormInfo.GetFormId());
184
185 {
186 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
187 if (!CheckKvStore()) {
188 HILOG_ERROR("kvStore is nullptr");
189 return ERR_APPEXECFWK_FORM_COMMON_CODE;
190 }
191 }
192
193 DistributedKv::Key key(formId);
194 DistributedKv::Value value(innerFormInfo.ToString());
195 DistributedKv::Status status;
196 {
197 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
198 status = kvStorePtr_->Put(key, value);
199 if (status == DistributedKv::Status::IPC_ERROR) {
200 status = kvStorePtr_->Put(key, value);
201 HILOG_WARN("distribute database ipc error and try to call again, result = %{public}d", status);
202 }
203 }
204 if (status != DistributedKv::Status::SUCCESS) {
205 HILOG_ERROR("put innerFormInfo to kvStore error: %{public}d", status);
206 ret = ERR_APPEXECFWK_FORM_COMMON_CODE;
207 }
208 return ret;
209 }
210
211 /**
212 * @brief Modify the form data in DB.
213 * @param innerFormInfo Indicates the InnerFormInfo object to be Modify.
214 * @return Returns ERR_OK on success, others on failure.
215 */
ModifyStorageFormInfo(const InnerFormInfo & innerFormInfo)216 ErrCode FormStorageMgr::ModifyStorageFormInfo(const InnerFormInfo &innerFormInfo)
217 {
218 HILOG_INFO("%{public}s called, formId[%{public}" PRId64 "]", __func__, innerFormInfo.GetFormId());
219
220 ErrCode ret = ERR_OK;
221 std::string formId = std::to_string(innerFormInfo.GetFormId());
222 ret = DeleteStorageFormInfo(formId);
223 if (ret == ERR_OK) {
224 SaveStorageFormInfo(innerFormInfo);
225 }
226
227 return ret;
228 }
229
230 /**
231 * @brief Delete the form data in DB.
232 * @param formId The form data Id.
233 * @return Returns ERR_OK on success, others on failure.
234 */
DeleteStorageFormInfo(const std::string & formId)235 ErrCode FormStorageMgr::DeleteStorageFormInfo(const std::string &formId)
236 {
237 HILOG_INFO("%{public}s called, formId[%{public}s]", __func__, formId.c_str());
238
239 {
240 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
241 if (!CheckKvStore()) {
242 HILOG_ERROR("kvStore is nullptr");
243 return ERR_APPEXECFWK_FORM_COMMON_CODE;
244 }
245 }
246 DistributedKv::Key key(formId);
247 DistributedKv::Status status;
248
249 {
250 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
251 status = kvStorePtr_->Delete(key);
252 if (status == DistributedKv::Status::IPC_ERROR) {
253 status = kvStorePtr_->Delete(key);
254 HILOG_WARN("distribute database ipc error and try to call again, result = %{public}d", status);
255 }
256 }
257
258 if (status != DistributedKv::Status::SUCCESS) {
259 HILOG_ERROR("delete key error: %{public}d", status);
260 return ERR_APPEXECFWK_FORM_COMMON_CODE;
261 } else {
262 HILOG_ERROR("delete value to kvStore success");
263 }
264
265 return ERR_OK;
266 }
267
RegisterKvStoreDeathListener()268 void FormStorageMgr::RegisterKvStoreDeathListener()
269 {
270 HILOG_INFO("register kvStore death listener");
271 std::shared_ptr<DistributedKv::KvStoreDeathRecipient> callback =
272 std::make_shared<KvStoreDeathRecipientCallback>();
273 dataManager_.RegisterKvStoreServiceDeathRecipient(callback);
274 }
275
CheckKvStore()276 bool FormStorageMgr::CheckKvStore()
277 {
278 if (kvStorePtr_ != nullptr) {
279 return true;
280 }
281 int32_t tryTimes = MAX_TIMES;
282 while (tryTimes > 0) {
283 DistributedKv::Status status = GetKvStore();
284 if (status == DistributedKv::Status::SUCCESS && kvStorePtr_ != nullptr) {
285 return true;
286 }
287 HILOG_DEBUG("CheckKvStore, Times: %{public}d", tryTimes);
288 usleep(SLEEP_INTERVAL);
289 tryTimes--;
290 }
291 return kvStorePtr_ != nullptr;
292 }
293
GetKvStore()294 DistributedKv::Status FormStorageMgr::GetKvStore()
295 {
296 DistributedKv::Options options = {
297 .createIfMissing = true,
298 .encrypt = false,
299 .autoSync = false,
300 .kvStoreType = DistributedKv::KvStoreType::SINGLE_VERSION
301 };
302
303 DistributedKv::Status status = dataManager_.GetSingleKvStore(options, appId_, storeId_, kvStorePtr_);
304 if (status != DistributedKv::Status::SUCCESS) {
305 HILOG_ERROR("return error: %{public}d", status);
306 } else {
307 HILOG_INFO("get kvStore success");
308 }
309 return status;
310 }
311
GetEntries(std::vector<DistributedKv::Entry> & allEntries)312 DistributedKv::Status FormStorageMgr::GetEntries(std::vector<DistributedKv::Entry> &allEntries)
313 {
314 DistributedKv::Status status = DistributedKv::Status::ERROR;
315 // if prefix is empty, get all entries.
316 DistributedKv::Key key("");
317 if (kvStorePtr_) {
318 // sync call GetEntries, the callback will be trigger at once
319 status = kvStorePtr_->GetEntries(key, allEntries);
320 }
321 HILOG_INFO("get all entries status: %{public}d", status);
322 return status;
323 }
324
TryTwice(const std::function<DistributedKv::Status ()> & func)325 void FormStorageMgr::TryTwice(const std::function<DistributedKv::Status()> &func)
326 {
327 DistributedKv::Status status = func();
328 if (status == DistributedKv::Status::IPC_ERROR) {
329 status = func();
330 HILOG_WARN("distribute database ipc error and try to call again, result = %{public}d", status);
331 }
332 }
333
ResetKvStore()334 bool FormStorageMgr::ResetKvStore()
335 {
336 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
337 kvStorePtr_ = nullptr;
338 DistributedKv::Status status = GetKvStore();
339 if (status == DistributedKv::Status::SUCCESS && kvStorePtr_ != nullptr) {
340 return true;
341 }
342 HILOG_WARN("failed");
343 return false;
344 }
345 } // namespace AppExecFwk
346 } // namespace OHOS
347