1 /*
2 * Copyright (c) 2021-2022 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 #include "account_data_storage.h"
16 #include <memory>
17 #include <unistd.h>
18 #include "account_log_wrapper.h"
19 #include "account_hisysevent_adapter.h"
20
21 namespace OHOS {
22 namespace AccountSA {
23 const int32_t MAX_TIMES = 10;
24 const int32_t SLEEP_INTERVAL = 100 * 1000;
25 const std::string KV_STORE_EL1_BASE_DIR = "/data/service/el1/public/database/";
26 const std::string KV_STORE_EL2_BASE_DIR = "/data/service/el2/public/database/";
27
AccountDataStorage(const std::string & appId,const std::string & storeId,const AccountDataStorageOptions & options)28 AccountDataStorage::AccountDataStorage(const std::string &appId, const std::string &storeId,
29 const AccountDataStorageOptions &options)
30 {
31 appId_.appId = appId;
32 storeId_.storeId = storeId;
33 options_ = options;
34 if (options_.area == DistributedKv::EL1) {
35 baseDir_ = KV_STORE_EL1_BASE_DIR + appId;
36 } else {
37 baseDir_ = options.baseDir;
38 }
39 }
40
~AccountDataStorage()41 AccountDataStorage::~AccountDataStorage()
42 {
43 if (kvStorePtr_ != nullptr) {
44 dataManager_.CloseKvStore(appId_, kvStorePtr_);
45 }
46 }
47
TryTwice(const std::function<DistributedKv::Status ()> & func) const48 void AccountDataStorage::TryTwice(const std::function<DistributedKv::Status()> &func) const
49 {
50 OHOS::DistributedKv::Status status = func();
51 if (status == OHOS::DistributedKv::Status::IPC_ERROR) {
52 status = func();
53 ACCOUNT_LOGE("distribute database ipc error and try again, status = %{public}d", status);
54 }
55 }
56
GetKvStore()57 OHOS::DistributedKv::Status AccountDataStorage::GetKvStore()
58 {
59 OHOS::DistributedKv::Options options = {
60 .createIfMissing = true,
61 .encrypt = options_.encrypt,
62 .autoSync = options_.autoSync,
63 .syncable = options_.autoSync,
64 .securityLevel = options_.securityLevel,
65 .area = options_.area,
66 .kvStoreType = OHOS::DistributedKv::KvStoreType::SINGLE_VERSION,
67 .baseDir = baseDir_,
68 };
69
70 OHOS::DistributedKv::Status status = dataManager_.GetSingleKvStore(options, appId_, storeId_, kvStorePtr_);
71 if (status != OHOS::DistributedKv::Status::SUCCESS || kvStorePtr_ == nullptr) {
72 ACCOUNT_LOGE("GetSingleKvStore failed! status %{public}d, kvStorePtr_ is nullptr", status);
73 return status;
74 }
75 return status;
76 }
77
CheckKvStore()78 bool AccountDataStorage::CheckKvStore()
79 {
80 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
81
82 if (kvStorePtr_ != nullptr) {
83 return true;
84 }
85 int32_t tryTimes = MAX_TIMES;
86 OHOS::DistributedKv::Status status = OHOS::DistributedKv::Status::SUCCESS;
87 while (tryTimes > 0) {
88 status = GetKvStore();
89 if (status == OHOS::DistributedKv::Status::SUCCESS && kvStorePtr_ != nullptr) {
90 break;
91 }
92
93 usleep(SLEEP_INTERVAL);
94 tryTimes--;
95 }
96
97 if (kvStorePtr_ == nullptr) {
98 return false;
99 }
100
101 return true;
102 }
103
LoadAllData(std::map<std::string,std::shared_ptr<IAccountInfo>> & infos)104 ErrCode AccountDataStorage::LoadAllData(std::map<std::string, std::shared_ptr<IAccountInfo>> &infos)
105 {
106 if (!CheckKvStore()) {
107 ACCOUNT_LOGE("kvStore is nullptr");
108 return OHOS::ERR_OSACCOUNT_SERVICE_MANAGER_QUERY_DISTRIBUTE_DATA_ERROR;
109 }
110
111 OHOS::DistributedKv::Status status = DistributedKv::Status::SUCCESS;
112 std::vector<OHOS::DistributedKv::Entry> allEntries;
113 TryTwice([this, &status, &allEntries] {
114 status = GetEntries("", allEntries);
115 return status;
116 });
117
118 if (status != OHOS::DistributedKv::Status::SUCCESS) {
119 ACCOUNT_LOGE("get entries error: %{public}d", status);
120 return OHOS::ERR_OSACCOUNT_SERVICE_MANAGER_QUERY_DISTRIBUTE_DATA_ERROR;
121 }
122 infos.clear();
123 SaveEntries(allEntries, infos);
124 return ERR_OK;
125 }
126
AddAccountInfo(const IAccountInfo & iAccountInfo)127 ErrCode AccountDataStorage::AddAccountInfo(const IAccountInfo &iAccountInfo)
128 {
129 if (IsKeyExists(iAccountInfo.GetPrimeKey())) {
130 ACCOUNT_LOGE("the key already exists.");
131 return ERR_OSACCOUNT_SERVICE_DATA_STORAGE_KEY_EXISTED_ERROR;
132 }
133
134 std::string accountInfoStr = iAccountInfo.ToString();
135 if (accountInfoStr.empty()) {
136 ACCOUNT_LOGE("account info str is empty!");
137 return ERR_OSACCOUNT_SERVICE_ACCOUNT_INFO_EMPTY_ERROR;
138 }
139 return PutValueToKvStore(iAccountInfo.GetPrimeKey(), accountInfoStr);
140 }
141
SaveAccountInfo(const IAccountInfo & iAccountInfo)142 ErrCode AccountDataStorage::SaveAccountInfo(const IAccountInfo &iAccountInfo)
143 {
144 if (!IsKeyExists(iAccountInfo.GetPrimeKey())) {
145 ACCOUNT_LOGE("the key does not exist");
146 return ERR_OSACCOUNT_SERVICE_DATA_STORAGE_KEY_NOT_EXISTS_ERROR;
147 }
148
149 std::string accountInfoStr = iAccountInfo.ToString();
150 if (accountInfoStr.empty()) {
151 ACCOUNT_LOGE("account info str is empty!");
152 return ERR_OSACCOUNT_SERVICE_ACCOUNT_INFO_EMPTY_ERROR;
153 }
154 return PutValueToKvStore(iAccountInfo.GetPrimeKey(), accountInfoStr);
155 }
156
RemoveValueFromKvStore(const std::string & keyStr)157 ErrCode AccountDataStorage::RemoveValueFromKvStore(const std::string &keyStr)
158 {
159 if (!CheckKvStore()) {
160 ACCOUNT_LOGE("kvStore is nullptr");
161 return ERR_ACCOUNT_COMMON_CHECK_KVSTORE_ERROR;
162 }
163
164 OHOS::DistributedKv::Key key(keyStr);
165 OHOS::DistributedKv::Status status;
166 OHOS::DistributedKv::Value value;
167 {
168 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
169 // check exist
170 status = kvStorePtr_->Get(key, value);
171 if (status == OHOS::DistributedKv::Status::IPC_ERROR) {
172 ACCOUNT_LOGE("kvstore ipc error and try again, status = %{public}d", status);
173 status = kvStorePtr_->Get(key, value);
174 }
175 if (status != OHOS::DistributedKv::Status::SUCCESS) {
176 ACCOUNT_LOGI("key does not exist in kvStore.");
177 return ERR_OK;
178 }
179
180 // delete
181 status = kvStorePtr_->Delete(key);
182 if (status == OHOS::DistributedKv::Status::IPC_ERROR) {
183 status = kvStorePtr_->Delete(key);
184 ACCOUNT_LOGE("kvstore ipc error and try to call again, status = %{public}d", status);
185 }
186 }
187
188 if (status != OHOS::DistributedKv::Status::SUCCESS) {
189 ACCOUNT_LOGE("delete key from kvstore failed, status %{public}d.", status);
190 return ERR_ACCOUNT_COMMON_DELETE_KEY_FROM_KVSTORE_ERROR;
191 }
192
193 ACCOUNT_LOGD("delete key from kvStore succeed!");
194 return ERR_OK;
195 }
196
GetEntries(std::string subId,std::vector<OHOS::DistributedKv::Entry> & allEntries) const197 OHOS::DistributedKv::Status AccountDataStorage::GetEntries(
198 std::string subId, std::vector<OHOS::DistributedKv::Entry> &allEntries) const
199 {
200 OHOS::DistributedKv::Key allEntryKeyPrefix(subId);
201 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
202 OHOS::DistributedKv::Status status = kvStorePtr_->GetEntries(allEntryKeyPrefix, allEntries);
203
204 return status;
205 }
206
DeleteKvStore()207 ErrCode AccountDataStorage::DeleteKvStore()
208 {
209 if (!CheckKvStore()) {
210 ACCOUNT_LOGE("kvStore is nullptr");
211 return OHOS::ERR_OSACCOUNT_SERVICE_MANAGER_QUERY_DISTRIBUTE_DATA_ERROR;
212 }
213
214 OHOS::DistributedKv::Status status;
215 {
216 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
217 dataManager_.CloseKvStore(this->appId_, this->storeId_);
218 status = dataManager_.DeleteKvStore(this->appId_, this->storeId_, baseDir_);
219 }
220 if (status != OHOS::DistributedKv::Status::SUCCESS) {
221 ACCOUNT_LOGE("error, status = %{public}d", status);
222 return OHOS::ERR_OSACCOUNT_SERVICE_MANAGER_QUERY_DISTRIBUTE_DATA_ERROR;
223 }
224
225 return ERR_OK;
226 }
227
GetAccountInfoById(const std::string id,IAccountInfo & iAccountInfo)228 ErrCode AccountDataStorage::GetAccountInfoById(const std::string id, IAccountInfo &iAccountInfo)
229 {
230 std::string valueStr;
231 ErrCode ret = GetValueFromKvStore(id, valueStr);
232 if (ret != ERR_OK) {
233 ACCOUNT_LOGE("get value from kvstore failed! id %{public}s.", id.c_str());
234 return ret;
235 }
236
237 nlohmann::json jsonObject = nlohmann::json::parse(valueStr, nullptr, false);
238 if (jsonObject.is_discarded() || !jsonObject.is_structured()) { // check format
239 ACCOUNT_LOGE("bad format of value from kvstore! id %{public}s.", id.c_str());
240 return ERR_ACCOUNT_COMMON_BAD_JSON_FORMAT_ERROR;
241 }
242 iAccountInfo.FromJson(jsonObject);
243 return ERR_OK;
244 }
245
LoadDataByLocalFuzzyQuery(std::string subId,std::map<std::string,std::shared_ptr<IAccountInfo>> & infos)246 ErrCode AccountDataStorage::LoadDataByLocalFuzzyQuery(
247 std::string subId, std::map<std::string, std::shared_ptr<IAccountInfo>> &infos)
248 {
249 if (!CheckKvStore()) {
250 ACCOUNT_LOGE("kvStore is nullptr");
251 return OHOS::ERR_OSACCOUNT_SERVICE_MANAGER_QUERY_DISTRIBUTE_DATA_ERROR;
252 }
253
254 OHOS::DistributedKv::Status status = OHOS::DistributedKv::Status::SUCCESS;
255 std::vector<OHOS::DistributedKv::Entry> allEntries;
256 TryTwice([this, &status, &allEntries, subId] {
257 status = GetEntries(subId, allEntries);
258 return status;
259 });
260
261 if (status != OHOS::DistributedKv::Status::SUCCESS) {
262 ACCOUNT_LOGE("get entries error: %{public}d", status);
263 return OHOS::ERR_OSACCOUNT_SERVICE_MANAGER_QUERY_DISTRIBUTE_DATA_ERROR;
264 }
265 infos.clear();
266 SaveEntries(allEntries, infos);
267 return ERR_OK;
268 }
269
PutValueToKvStore(const std::string & keyStr,const std::string & valueStr)270 ErrCode AccountDataStorage::PutValueToKvStore(const std::string &keyStr, const std::string &valueStr)
271 {
272 if (!CheckKvStore()) {
273 ACCOUNT_LOGE("kvStore is nullptr");
274 return ERR_ACCOUNT_COMMON_CHECK_KVSTORE_ERROR;
275 }
276
277 OHOS::DistributedKv::Key key(keyStr);
278 OHOS::DistributedKv::Value value(valueStr);
279 OHOS::DistributedKv::Status status;
280
281 {
282 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
283 status = kvStorePtr_->Put(key, value);
284 if (status == OHOS::DistributedKv::Status::IPC_ERROR) {
285 status = kvStorePtr_->Put(key, value);
286 }
287 }
288
289 if (status != OHOS::DistributedKv::Status::SUCCESS) {
290 ACCOUNT_LOGE("put value to kvStore error, status = %{public}d", status);
291 return OHOS::ERR_OSACCOUNT_SERVICE_MANAGER_QUERY_DISTRIBUTE_DATA_ERROR;
292 }
293
294 return ERR_OK;
295 }
296
GetValueFromKvStore(const std::string & keyStr,std::string & valueStr)297 ErrCode AccountDataStorage::GetValueFromKvStore(const std::string &keyStr, std::string &valueStr)
298 {
299 if (!CheckKvStore()) {
300 ACCOUNT_LOGE("kvStore is nullptr");
301 return ERR_ACCOUNT_COMMON_CHECK_KVSTORE_ERROR;
302 }
303
304 OHOS::DistributedKv::Key key(keyStr);
305 OHOS::DistributedKv::Value value;
306 OHOS::DistributedKv::Status status;
307
308 {
309 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
310 status = kvStorePtr_->Get(key, value);
311 if (status == OHOS::DistributedKv::Status::IPC_ERROR) {
312 ACCOUNT_LOGE("kvstore ipc error and try again, status = %{public}d", status);
313 status = kvStorePtr_->Get(key, value);
314 }
315 }
316
317 if (status != OHOS::DistributedKv::Status::SUCCESS) {
318 ACCOUNT_LOGE("get value from kvstore error, status %{public}d.", status);
319 return ERR_OSACCOUNT_SERVICE_MANAGER_QUERY_DISTRIBUTE_DATA_ERROR;
320 }
321
322 valueStr = value.ToString();
323 return ERR_OK;
324 }
325
IsKeyExists(const std::string keyStr)326 bool AccountDataStorage::IsKeyExists(const std::string keyStr)
327 {
328 std::string valueStr;
329 if (GetValueFromKvStore(keyStr, valueStr) != ERR_OK) {
330 return false;
331 }
332 return true;
333 }
334
MoveData(const std::shared_ptr<AccountDataStorage> & ptr)335 ErrCode AccountDataStorage::MoveData(const std::shared_ptr<AccountDataStorage> &ptr)
336 {
337 if (ptr == nullptr || !ptr->CheckKvStore() || !CheckKvStore()) {
338 ACCOUNT_LOGE("AccountDataStorage is nullptr");
339 return ERR_ACCOUNT_COMMON_CHECK_KVSTORE_ERROR;
340 }
341 std::vector<OHOS::DistributedKv::Entry> entries;
342 OHOS::DistributedKv::Status status = ptr->GetEntries("", entries);
343 if (status != OHOS::DistributedKv::Status::SUCCESS) {
344 ACCOUNT_LOGE("GetEntries failed, result=%{public}u", status);
345 return ERR_OSACCOUNT_SERVICE_MANAGER_QUERY_DISTRIBUTE_DATA_ERROR;
346 }
347 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
348 status = kvStorePtr_->PutBatch(entries);
349 if (status != OHOS::DistributedKv::Status::SUCCESS) {
350 ACCOUNT_LOGE("PutBatch failed, result=%{public}u", status);
351 return ERR_OSACCOUNT_SERVICE_MANAGER_QUERY_DISTRIBUTE_DATA_ERROR;
352 }
353 return ERR_OK;
354 }
355 } // namespace AccountSA
356 } // namespace OHOS
357