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_LOGD("PreInstall instance is created");
34 TryTwice([this] { return GetKvStore(); });
35 }
36
~PreInstallDataStorage()37 PreInstallDataStorage::~PreInstallDataStorage()
38 {
39 APP_LOGD("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_LOGD("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 std::map<std::string, PreInstallBundleInfo> updateInfos;
105 for (const auto &item : allEntries) {
106 PreInstallBundleInfo preInstallBundleInfo;
107 nlohmann::json jsonObject = nlohmann::json::parse(item.value.ToString(), nullptr, false);
108 if (jsonObject.is_discarded()) {
109 APP_LOGE("jsonObject is discarded error key: %{public}s", item.key.ToString().c_str());
110 // it's an bad json, delete it
111 {
112 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
113 kvStorePtr_->Delete(item.key);
114 }
115 continue;
116 }
117
118 if (preInstallBundleInfo.FromJson(jsonObject) != ERR_OK) {
119 APP_LOGE("error key: %{private}s", item.key.ToString().c_str());
120 // it's an error value, delete it
121 {
122 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
123 kvStorePtr_->Delete(item.key);
124 }
125 continue;
126 }
127 preInstallBundleInfos.emplace_back(preInstallBundleInfo);
128 // database update
129 std::string key = item.key.ToString();
130 if (key != preInstallBundleInfo.GetBundleName()) {
131 updateInfos.emplace(key, preInstallBundleInfo);
132 }
133 }
134 if (updateInfos.size() > 0) {
135 UpdateDataBase(updateInfos);
136 }
137 APP_LOGD("PreInstall SaveEntries end");
138 }
139
LoadAllPreInstallBundleInfos(std::vector<PreInstallBundleInfo> & preInstallBundleInfos)140 bool PreInstallDataStorage::LoadAllPreInstallBundleInfos(std::vector<PreInstallBundleInfo> &preInstallBundleInfos)
141 {
142 APP_LOGD("load all preInstallBundleInfo data to vector start.");
143 {
144 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
145 if (!CheckKvStore()) {
146 APP_LOGE("kvStore is nullptr");
147 return false;
148 }
149 }
150
151 Status status;
152 std::vector<Entry> allEntries;
153 TryTwice([this, &status, &allEntries] {
154 status = GetEntries(allEntries);
155 return status;
156 });
157
158 if (status != Status::SUCCESS) {
159 APP_LOGE("get entries error: %{public}d", status);
160 // KEY_NOT_FOUND means no data in database, no need to report.
161 if (status != Status::KEY_NOT_FOUND) {
162 const std::string interfaceName = "KvStoreSnapshot::GetEntries()";
163 }
164 return false;
165 }
166
167 SaveEntries(allEntries, preInstallBundleInfos);
168 return true;
169 }
170
GetEntries(std::vector<Entry> & allEntries) const171 Status PreInstallDataStorage::GetEntries(std::vector<Entry> &allEntries) const
172 {
173 Status status = Status::ERROR;
174 Key token;
175 // if prefix is empty, get all entries.
176 Key allEntryKeyPrefix("");
177 if (kvStorePtr_) {
178 // sync call GetEntries, the callback will be trigger at once
179 status = kvStorePtr_->GetEntries(allEntryKeyPrefix, allEntries);
180 }
181 APP_LOGD("get all entries status: %{public}d", status);
182 return status;
183 }
184
SavePreInstallStorageBundleInfo(const PreInstallBundleInfo & preInstallBundleInfo)185 bool PreInstallDataStorage::SavePreInstallStorageBundleInfo(const PreInstallBundleInfo &preInstallBundleInfo)
186 {
187 APP_LOGD("save PreInstall bundle data.");
188 {
189 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
190 if (!CheckKvStore()) {
191 APP_LOGE("kvStore is nullptr");
192 return false;
193 }
194 }
195 std::string keyInfo = preInstallBundleInfo.GetBundleName();
196 std::string valueInfo = preInstallBundleInfo.ToString();
197 Key key(keyInfo);
198 Value value(valueInfo);
199 APP_LOGD("save PreInstallStorageBundleInfo, key: %{public}s value: %{public}s.",
200 keyInfo.c_str(), valueInfo.c_str());
201 Status status;
202 {
203 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
204 status = kvStorePtr_->Put(key, value);
205 if (status == Status::IPC_ERROR) {
206 status = kvStorePtr_->Put(key, value);
207 APP_LOGD("distribute database ipc error and try to call again, result = %{public}d", status);
208 }
209 }
210
211 if (status != Status::SUCCESS) {
212 APP_LOGD("put valLocalAbilityManager::InitializeSaProfilesue to kvStore error: %{public}d", status);
213 return false;
214 }
215 APP_LOGD("put value to kvStore success when save PreInstall bundle data.");
216 return true;
217 }
218
DeletePreInstallStorageBundleInfo(const PreInstallBundleInfo & preInstallBundleInfo)219 bool PreInstallDataStorage::DeletePreInstallStorageBundleInfo(const PreInstallBundleInfo &preInstallBundleInfo)
220 {
221 APP_LOGD("delete PreInstall bundle data");
222 {
223 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
224 if (!CheckKvStore()) {
225 APP_LOGE("kvStore is nullptr");
226 return false;
227 }
228 }
229 std::string keyInfo = preInstallBundleInfo.GetBundleName();
230 Key key(keyInfo);
231 APP_LOGD("delete PreInstallStorageBundleInfo, key: %{public}s", keyInfo.c_str());
232 Status status;
233
234 {
235 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
236 status = kvStorePtr_->Delete(key);
237 if (status == Status::IPC_ERROR) {
238 status = kvStorePtr_->Delete(key);
239 APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
240 }
241 }
242
243 if (status != Status::SUCCESS) {
244 APP_LOGE("delete key error: %{public}d", status);
245 return false;
246 } else {
247 APP_LOGD("delete value to kvStore success");
248 }
249 return true;
250 }
251
UpdateDataBase(std::map<std::string,PreInstallBundleInfo> & infos)252 void PreInstallDataStorage::UpdateDataBase(std::map<std::string, PreInstallBundleInfo>& infos)
253 {
254 APP_LOGD("begin to update preInstall database.");
255 for (const auto& item : infos) {
256 if (SavePreInstallStorageBundleInfo(item.second)) {
257 DeleteOldBundleInfo(item.first);
258 }
259 }
260 APP_LOGD("update preInstall database done.");
261 }
262
DeleteOldBundleInfo(const std::string & oldKey)263 void PreInstallDataStorage::DeleteOldBundleInfo(const std::string& oldKey)
264 {
265 APP_LOGD("begin to delete old preInstall bundleInfo");
266 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
267 if (!CheckKvStore()) {
268 APP_LOGE("kvStore is nullptr");
269 return;
270 }
271 Key key(oldKey);
272 Status status = kvStorePtr_->Delete(key);
273 if (status == Status::IPC_ERROR) {
274 status = kvStorePtr_->Delete(key);
275 APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
276 }
277 if (status != Status::SUCCESS) {
278 APP_LOGE("delete old bundleInfo failed: %{public}d", status);
279 return;
280 }
281 APP_LOGD("delete old preInstall bundleInfo success");
282 }
283 } // namespace AppExecFwk
284 } // namespace OHOS
285