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