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