• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "bundle_data_storage_database.h"
17 
18 #include <unistd.h>
19 #include "app_log_wrapper.h"
20 #include "kvstore_death_recipient_callback.h"
21 
22 using namespace OHOS::DistributedKv;
23 
24 namespace OHOS {
25 namespace AppExecFwk {
26 namespace {
27 
28 const int32_t MAX_TIMES = 600;              // 1min
29 const int32_t SLEEP_INTERVAL = 100 * 1000;  // 100ms
30 
31 }  // namespace
32 
BundleDataStorageDatabase()33 BundleDataStorageDatabase::BundleDataStorageDatabase()
34 {
35     APP_LOGI("instance:%{private}p is created", this);
36     TryTwice([this] { return GetKvStore(); });
37     RegisterKvStoreDeathListener();
38 }
39 
~BundleDataStorageDatabase()40 BundleDataStorageDatabase::~BundleDataStorageDatabase()
41 {
42     APP_LOGI("instance:%{private}p is destroyed", this);
43     dataManager_.CloseKvStore(appId_, std::move(kvStorePtr_));
44 }
45 
KeyToDeviceAndName(const std::string & key,std::string & deviceId,std::string & bundleName) const46 bool BundleDataStorageDatabase::KeyToDeviceAndName(
47     const std::string &key, std::string &deviceId, std::string &bundleName) const
48 {
49     const size_t underlinePos = key.find_first_of(Constants::FILE_UNDERLINE);
50     if (underlinePos == std::string::npos) {
51         APP_LOGW("invalid key : %{private}s", key.c_str());
52         return false;
53     }
54     deviceId = key.substr(0, underlinePos);
55     bundleName = key.substr(underlinePos + 1);
56     return true;
57 }
58 
DeviceAndNameToKey(const std::string & deviceId,const std::string & bundleName,std::string & key) const59 void BundleDataStorageDatabase::DeviceAndNameToKey(
60     const std::string &deviceId, const std::string &bundleName, std::string &key) const
61 {
62     key.append(deviceId);
63     key.append(Constants::FILE_UNDERLINE);
64     key.append(bundleName);
65     APP_LOGD("bundleName = %{public}s", bundleName.c_str());
66 }
67 
SaveEntries(const std::vector<Entry> & allEntries,std::map<std::string,std::map<std::string,InnerBundleInfo>> & infos) const68 void BundleDataStorageDatabase::SaveEntries(
69     const std::vector<Entry> &allEntries, std::map<std::string, std::map<std::string, InnerBundleInfo>> &infos) const
70 {
71     for (const auto &item : allEntries) {
72         std::string bundleName;
73         std::string deviceId;
74         InnerBundleInfo innerBundleInfo;
75         if (!KeyToDeviceAndName(item.key.ToString(), deviceId, bundleName)) {
76             APP_LOGE("error key: %{private}s", item.key.ToString().c_str());
77             // it's an error key, delete it
78             {
79                 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
80                 kvStorePtr_->Delete(item.key);
81             }
82             continue;
83         }
84 
85         nlohmann::json jsonObject = nlohmann::json::parse(item.value.ToString(), nullptr, false);
86         if (jsonObject.is_discarded()) {
87             APP_LOGE("error key: %{private}s", item.key.ToString().c_str());
88             // it's an bad json, delete it
89             {
90                 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
91                 kvStorePtr_->Delete(item.key);
92             }
93             continue;
94         }
95         if (innerBundleInfo.FromJson(jsonObject) != ERR_OK) {
96             APP_LOGE("error key: %{private}s", item.key.ToString().c_str());
97             // it's an error value, delete it
98             {
99                 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
100                 kvStorePtr_->Delete(item.key);
101             }
102             continue;
103         }
104 
105         auto allDevicesInfosIter = infos.find(bundleName);
106         if (allDevicesInfosIter != infos.end()) {
107             APP_LOGD("already have bundle: %{public}s", bundleName.c_str());
108             allDevicesInfosIter->second.emplace(deviceId, innerBundleInfo);
109         } else {
110             APP_LOGD("emplace bundle: %{public}s", bundleName.c_str());
111             std::map<std::string, InnerBundleInfo> allDevicesInfos;
112             allDevicesInfos.emplace(deviceId, innerBundleInfo);
113             infos.emplace(bundleName, allDevicesInfos);
114         }
115     }
116     APP_LOGD("SaveEntries end");
117 }
118 
LoadAllData(std::map<std::string,std::map<std::string,InnerBundleInfo>> & infos)119 bool BundleDataStorageDatabase::LoadAllData(std::map<std::string, std::map<std::string, InnerBundleInfo>> &infos)
120 {
121     APP_LOGI("load all installed bundle data to map");
122     {
123         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
124         if (!CheckKvStore()) {
125             APP_LOGE("kvStore is nullptr");
126             return false;
127         }
128     }
129     Status status;
130     std::vector<Entry> allEntries;
131     TryTwice([this, &status, &allEntries] {
132         status = GetEntries(allEntries);
133         return status;
134     });
135 
136     bool ret = true;
137     if (status != Status::SUCCESS) {
138         APP_LOGE("get entries error: %{public}d", status);
139         // KEY_NOT_FOUND means no data in database, no need to report.
140         if (status != Status::KEY_NOT_FOUND) {
141             const std::string interfaceName = "KvStoreSnapshot::GetEntries()";
142         }
143         ret = false;
144     } else {
145         SaveEntries(allEntries, infos);
146     }
147     return ret;
148 }
149 
SaveStorageBundleInfo(const std::string & deviceId,const InnerBundleInfo & innerBundleInfo)150 bool BundleDataStorageDatabase::SaveStorageBundleInfo(
151     const std::string &deviceId, const InnerBundleInfo &innerBundleInfo)
152 {
153     APP_LOGI("save bundle data");
154     {
155         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
156         if (!CheckKvStore()) {
157             APP_LOGE("kvStore is nullptr");
158             return false;
159         }
160     }
161 
162     std::string keyOfData;
163     DeviceAndNameToKey(deviceId, innerBundleInfo.GetBundleName(), keyOfData);
164     Key key(keyOfData);
165     Value value(innerBundleInfo.ToString());
166     Status status;
167     {
168         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
169         status = kvStorePtr_->Put(key, value);
170         if (status == Status::IPC_ERROR) {
171             status = kvStorePtr_->Put(key, value);
172             APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
173         }
174     }
175     if (status != Status::SUCCESS) {
176         const std::string interfaceName = "kvStorePtr::Put()";
177         APP_LOGE("put valLocalAbilityManager::InitializeSaProfilesue to kvStore error: %{public}d", status);
178         return false;
179     } else {
180         APP_LOGE("put value to kvStore success");
181     }
182     return true;
183 }
184 
DeleteStorageBundleInfo(const std::string & deviceId,const InnerBundleInfo & innerBundleInfo)185 bool BundleDataStorageDatabase::DeleteStorageBundleInfo(
186     const std::string &deviceId, const InnerBundleInfo &innerBundleInfo)
187 {
188     APP_LOGI("delete bundle data");
189     {
190         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
191         if (!CheckKvStore()) {
192             APP_LOGE("kvStore is nullptr");
193             return false;
194         }
195     }
196     std::string keyOfData;
197     DeviceAndNameToKey(deviceId, innerBundleInfo.GetBundleName(), keyOfData);
198     Key key(keyOfData);
199     Status status;
200 
201     {
202         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
203         status = kvStorePtr_->Delete(key);
204         if (status == Status::IPC_ERROR) {
205             status = kvStorePtr_->Delete(key);
206             APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
207         }
208     }
209 
210     if (status != Status::SUCCESS) {
211         const std::string interfaceName = "kvStorePtr::Delete()";
212         APP_LOGE("delete key error: %{public}d", status);
213         return false;
214     } else {
215         APP_LOGE("delete value to kvStore success");
216     }
217     return true;
218 }
219 
RegisterKvStoreDeathListener()220 void BundleDataStorageDatabase::RegisterKvStoreDeathListener()
221 {
222     APP_LOGI("register kvStore death listener");
223     std::shared_ptr<DistributedKv::KvStoreDeathRecipient> callback = std::make_shared<KvStoreDeathRecipientCallback>();
224     dataManager_.RegisterKvStoreServiceDeathRecipient(callback);
225 }
226 
CheckKvStore()227 bool BundleDataStorageDatabase::CheckKvStore()
228 {
229     if (kvStorePtr_ != nullptr) {
230         return true;
231     }
232     int32_t tryTimes = MAX_TIMES;
233     while (tryTimes > 0) {
234         Status status = GetKvStore();
235         if (status == Status::SUCCESS && kvStorePtr_ != nullptr) {
236             return true;
237         }
238         APP_LOGD("CheckKvStore, Times: %{public}d", tryTimes);
239         usleep(SLEEP_INTERVAL);
240         tryTimes--;
241     }
242     return kvStorePtr_ != nullptr;
243 }
244 
GetKvStore()245 Status BundleDataStorageDatabase::GetKvStore()
246 {
247     Status status;
248     Options options = {
249         .createIfMissing = true,
250         .encrypt = false,
251         .autoSync = true,
252         .kvStoreType = KvStoreType::SINGLE_VERSION
253         };
254 
255     dataManager_.GetSingleKvStore(
256         options, appId_, storeId_, [this, &status](Status paramStatus, std::unique_ptr<SingleKvStore> singleKvStore) {
257             status = paramStatus;
258             if (status != Status::SUCCESS) {
259                 APP_LOGE("return error: %{public}d", status);
260                 return;
261             }
262             {
263                 kvStorePtr_ = std::move(singleKvStore);
264             }
265             APP_LOGI("get kvStore success");
266         });
267 
268     return status;
269 }
270 
GetEntries(std::vector<Entry> & allEntries) const271 Status BundleDataStorageDatabase::GetEntries(std::vector<Entry> &allEntries) const
272 {
273     Status status = Status::ERROR;
274     Key token;
275     // if prefix is empty, get all entries.
276     Key allEntryKeyPrefix("");
277     if (kvStorePtr_) {
278         // sync call GetEntries, the callback will be trigger at once
279         status = kvStorePtr_->GetEntries(allEntryKeyPrefix, allEntries);
280     }
281     APP_LOGI("get all entries status: %{public}d", status);
282     return status;
283 }
284 
TryTwice(const std::function<Status ()> & func) const285 void BundleDataStorageDatabase::TryTwice(const std::function<Status()> &func) const
286 {
287     Status status = func();
288     if (status == Status::IPC_ERROR) {
289         status = func();
290         APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
291     }
292 }
293 
ResetKvStore()294 bool BundleDataStorageDatabase::ResetKvStore()
295 {
296     std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
297     kvStorePtr_ = nullptr;
298     Status status = GetKvStore();
299     if (status == Status::SUCCESS && kvStorePtr_ != nullptr) {
300         return true;
301     }
302     APP_LOGW("failed");
303     return false;
304 }
305 
306 }  // namespace AppExecFwk
307 }  // namespace OHOS