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