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