1 /*
2 * Copyright (c) 2024 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 "ability_keep_alive_data_manager.h"
17
18 #include <unistd.h>
19
20 #include "hilog_tag_wrapper.h"
21 #include "json_utils.h"
22
23 namespace OHOS {
24 namespace AbilityRuntime {
25 namespace {
26 constexpr int32_t CHECK_INTERVAL = 100000; // 100ms
27 constexpr int32_t MAX_TIMES = 5; // 5 * 100ms = 500ms
28 constexpr const char *KEEP_ALIVE_STORAGE_DIR = "/data/service/el1/public/database/keep_alive_service";
29 const std::string JSON_KEY_BUNDLE_NAME = "bundleName";
30 const std::string JSON_KEY_USERID = "userId";
31 const std::string JSON_KEY_APP_TYPE = "appType";
32 const std::string JSON_KEY_SETTER = "setter";
33 } // namespace
34 const DistributedKv::AppId AbilityKeepAliveDataManager::APP_ID = { "keep_alive_storage" };
35 const DistributedKv::StoreId AbilityKeepAliveDataManager::STORE_ID = { "keep_alive_infos" };
36
GetInstance()37 AbilityKeepAliveDataManager &AbilityKeepAliveDataManager::GetInstance()
38 {
39 static AbilityKeepAliveDataManager instance;
40 return instance;
41 }
42
AbilityKeepAliveDataManager()43 AbilityKeepAliveDataManager::AbilityKeepAliveDataManager() {}
44
~AbilityKeepAliveDataManager()45 AbilityKeepAliveDataManager::~AbilityKeepAliveDataManager()
46 {
47 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
48 if (kvStorePtr_ != nullptr) {
49 dataManager_.CloseKvStore(APP_ID, kvStorePtr_);
50 }
51 }
52
RestoreKvStore(DistributedKv::Status status)53 DistributedKv::Status AbilityKeepAliveDataManager::RestoreKvStore(DistributedKv::Status status)
54 {
55 if (status == DistributedKv::Status::DATA_CORRUPTED) {
56 DistributedKv::Options options = {
57 .createIfMissing = true,
58 .encrypt = false,
59 .autoSync = false,
60 .syncable = false,
61 .securityLevel = DistributedKv::SecurityLevel::S2,
62 .area = DistributedKv::EL1,
63 .kvStoreType = DistributedKv::KvStoreType::SINGLE_VERSION,
64 .baseDir = KEEP_ALIVE_STORAGE_DIR,
65 };
66 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "corrupted, deleting db");
67 dataManager_.DeleteKvStore(APP_ID, STORE_ID, options.baseDir);
68 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "deleted corrupted db, recreating db");
69 status = dataManager_.GetSingleKvStore(options, APP_ID, STORE_ID, kvStorePtr_);
70 TAG_LOGI(AAFwkTag::KEEP_ALIVE, "recreate db result:%{public}d", status);
71 }
72 return status;
73 }
74
GetKvStore()75 DistributedKv::Status AbilityKeepAliveDataManager::GetKvStore()
76 {
77 DistributedKv::Options options = {
78 .createIfMissing = true,
79 .encrypt = false,
80 .autoSync = false,
81 .syncable = false,
82 .securityLevel = DistributedKv::SecurityLevel::S2,
83 .area = DistributedKv::EL1,
84 .kvStoreType = DistributedKv::KvStoreType::SINGLE_VERSION,
85 .baseDir = KEEP_ALIVE_STORAGE_DIR,
86 };
87
88 DistributedKv::Status status = dataManager_.GetSingleKvStore(options, APP_ID, STORE_ID, kvStorePtr_);
89 if (status != DistributedKv::Status::SUCCESS) {
90 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "Error: %{public}d", status);
91 status = RestoreKvStore(status);
92 return status;
93 }
94
95 TAG_LOGD(AAFwkTag::KEEP_ALIVE, "Get kvStore success");
96 return status;
97 }
98
CheckKvStore()99 bool AbilityKeepAliveDataManager::CheckKvStore()
100 {
101 if (kvStorePtr_ != nullptr) {
102 return true;
103 }
104 int32_t tryTimes = MAX_TIMES;
105 while (tryTimes > 0) {
106 DistributedKv::Status status = GetKvStore();
107 if (status == DistributedKv::Status::SUCCESS && kvStorePtr_ != nullptr) {
108 return true;
109 }
110 TAG_LOGD(AAFwkTag::KEEP_ALIVE, "Try times: %{public}d", tryTimes);
111 usleep(CHECK_INTERVAL);
112 tryTimes--;
113 }
114 return kvStorePtr_ != nullptr;
115 }
116
InsertKeepAliveData(const KeepAliveInfo & info)117 int32_t AbilityKeepAliveDataManager::InsertKeepAliveData(const KeepAliveInfo &info)
118 {
119 if (info.bundleName.empty() || info.userId < 0
120 || info.appType == KeepAliveAppType::UNSPECIFIED
121 || info.setter == KeepAliveSetter::UNSPECIFIED) {
122 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "Invalid value");
123 return ERR_INVALID_VALUE;
124 }
125
126 TAG_LOGD(AAFwkTag::KEEP_ALIVE,
127 "bundleName: %{public}s, userId: %{public}d, appType: %{public}d, setter: %{public}d",
128 info.bundleName.c_str(), info.userId, info.appType, info.setter);
129 {
130 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
131 if (!CheckKvStore()) {
132 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "null kvStore");
133 return ERR_NO_INIT;
134 }
135 }
136
137 DistributedKv::Key key = ConvertKeepAliveDataToKey(info);
138 DistributedKv::Value value = ConvertKeepAliveStatusToValue(info.setter);
139 DistributedKv::Status status;
140 {
141 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
142 status = kvStorePtr_->Put(key, value);
143 }
144
145 if (status != DistributedKv::Status::SUCCESS) {
146 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "kvStore insert error: %{public}d", status);
147 {
148 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
149 status = RestoreKvStore(status);
150 }
151 return ERR_INVALID_OPERATION;
152 }
153 return ERR_OK;
154 }
155
DeleteKeepAliveData(const KeepAliveInfo & info)156 int32_t AbilityKeepAliveDataManager::DeleteKeepAliveData(const KeepAliveInfo &info)
157 {
158 if (info.userId < 0) {
159 TAG_LOGW(AAFwkTag::KEEP_ALIVE, "Invalid value");
160 return ERR_INVALID_VALUE;
161 }
162
163 TAG_LOGD(AAFwkTag::KEEP_ALIVE,
164 "bundleName: %{public}s, userId: %{public}d, appType: %{public}d, setter: %{public}d",
165 info.bundleName.c_str(), info.userId, info.appType, info.setter);
166 {
167 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
168 if (!CheckKvStore()) {
169 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "null kvStore");
170 return ERR_NO_INIT;
171 }
172 }
173
174 std::vector<DistributedKv::Entry> allEntries;
175 DistributedKv::Status status = DistributedKv::Status::SUCCESS;
176 {
177 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
178 status = kvStorePtr_->GetEntries(nullptr, allEntries);
179 }
180 if (status != DistributedKv::Status::SUCCESS) {
181 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "GetEntries error: %{public}d", status);
182 {
183 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
184 status = RestoreKvStore(status);
185 }
186 return ERR_INVALID_OPERATION;
187 }
188
189 for (const auto &item : allEntries) {
190 if (IsEqual(item.key, info)) {
191 {
192 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
193 status = kvStorePtr_->Delete(item.key);
194 }
195 if (status != DistributedKv::Status::SUCCESS) {
196 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "kvStore delete error: %{public}d", status);
197 {
198 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
199 status = RestoreKvStore(status);
200 }
201 return ERR_INVALID_OPERATION;
202 }
203 }
204 }
205
206 return ERR_OK;
207 }
208
QueryKeepAliveData(const KeepAliveInfo & info)209 KeepAliveStatus AbilityKeepAliveDataManager::QueryKeepAliveData(const KeepAliveInfo &info)
210 {
211 KeepAliveStatus kaStatus;
212 if (info.bundleName.empty() || info.userId < 0) {
213 TAG_LOGW(AAFwkTag::KEEP_ALIVE, "Invalid value");
214 kaStatus.code = ERR_INVALID_VALUE;
215 return kaStatus;
216 }
217
218 TAG_LOGD(AAFwkTag::KEEP_ALIVE,
219 "bundleName: %{public}s, userId: %{public}d", info.bundleName.c_str(), info.userId);
220 {
221 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
222 if (!CheckKvStore()) {
223 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "null kvStore");
224 kaStatus.code = ERR_NO_INIT;
225 return kaStatus;
226 }
227 }
228
229 std::vector<DistributedKv::Entry> allEntries;
230 DistributedKv::Status status = DistributedKv::Status::SUCCESS;
231 {
232 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
233 status = kvStorePtr_->GetEntries(nullptr, allEntries);
234 }
235 if (status != DistributedKv::Status::SUCCESS) {
236 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "GetEntries error: %{public}d", status);
237 {
238 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
239 status = RestoreKvStore(status);
240 }
241 kaStatus.code = ERR_INVALID_OPERATION;
242 return kaStatus;
243 }
244
245 kaStatus.code = ERR_NAME_NOT_FOUND;
246 for (const auto &item : allEntries) {
247 if (IsEqual(item.key, info)) {
248 ConvertKeepAliveStatusFromValue(item.value, kaStatus.setter);
249 kaStatus.code = ERR_OK;
250 break;
251 }
252 }
253
254 return kaStatus;
255 }
256
QueryKeepAliveApplications(const KeepAliveInfo & queryParam,std::vector<KeepAliveInfo> & infoList)257 int32_t AbilityKeepAliveDataManager::QueryKeepAliveApplications(
258 const KeepAliveInfo &queryParam, std::vector<KeepAliveInfo> &infoList)
259 {
260 if (queryParam.userId < 0) {
261 TAG_LOGW(AAFwkTag::KEEP_ALIVE, "Invalid value");
262 return ERR_INVALID_VALUE;
263 }
264
265 TAG_LOGD(AAFwkTag::KEEP_ALIVE,
266 "bundleName: %{public}s, userId: %{public}d, appType: %{public}d, setter: %{public}d",
267 queryParam.bundleName.c_str(), queryParam.userId, queryParam.appType, queryParam.setter);
268 {
269 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
270 if (!CheckKvStore()) {
271 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "null kvStore");
272 return ERR_NO_INIT;
273 }
274 }
275
276 std::vector<DistributedKv::Entry> allEntries;
277 DistributedKv::Status status = DistributedKv::Status::SUCCESS;
278 {
279 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
280 status = kvStorePtr_->GetEntries(nullptr, allEntries);
281 }
282 if (status != DistributedKv::Status::SUCCESS) {
283 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "GetEntries: %{public}d", status);
284 {
285 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
286 status = RestoreKvStore(status);
287 }
288 return ERR_INVALID_OPERATION;
289 }
290
291 for (const auto &item : allEntries) {
292 if (!IsEqual(item.key, queryParam)) {
293 continue;
294 }
295 infoList.emplace_back(ConvertKeepAliveInfoFromKey(item.key));
296 }
297 TAG_LOGD(AAFwkTag::KEEP_ALIVE, "InfoList.size: %{public}zu", infoList.size());
298 return ERR_OK;
299 }
300
ConvertKeepAliveStatusToValue(KeepAliveSetter setter)301 DistributedKv::Value AbilityKeepAliveDataManager::ConvertKeepAliveStatusToValue(KeepAliveSetter setter)
302 {
303 nlohmann::json jsonObject = nlohmann::json {
304 { JSON_KEY_SETTER, setter },
305 };
306 DistributedKv::Value value(jsonObject.dump());
307 TAG_LOGD(AAFwkTag::KEEP_ALIVE, "value: %{public}s", value.ToString().c_str());
308 return value;
309 }
310
ConvertKeepAliveStatusFromValue(const DistributedKv::Value & value,KeepAliveSetter & setter)311 void AbilityKeepAliveDataManager::ConvertKeepAliveStatusFromValue(const DistributedKv::Value &value,
312 KeepAliveSetter &setter)
313 {
314 nlohmann::json jsonObject = nlohmann::json::parse(value.ToString(), nullptr, false);
315 if (jsonObject.is_discarded()) {
316 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "parse jsonObject fail");
317 return;
318 }
319 if (jsonObject.contains(JSON_KEY_SETTER) && jsonObject[JSON_KEY_SETTER].is_number()) {
320 setter = KeepAliveSetter(jsonObject.at(JSON_KEY_SETTER).get<int32_t>());
321 }
322 }
323
ConvertKeepAliveDataToKey(const KeepAliveInfo & info)324 DistributedKv::Key AbilityKeepAliveDataManager::ConvertKeepAliveDataToKey(const KeepAliveInfo &info)
325 {
326 nlohmann::json jsonObject = nlohmann::json {
327 { JSON_KEY_BUNDLE_NAME, info.bundleName },
328 { JSON_KEY_USERID, info.userId },
329 { JSON_KEY_APP_TYPE, info.appType },
330 { JSON_KEY_SETTER, info.setter },
331 };
332 DistributedKv::Key key(jsonObject.dump());
333 TAG_LOGD(AAFwkTag::KEEP_ALIVE, "key: %{public}s", key.ToString().c_str());
334 return key;
335 }
336
ConvertKeepAliveInfoFromKey(const DistributedKv::Key & key)337 KeepAliveInfo AbilityKeepAliveDataManager::ConvertKeepAliveInfoFromKey(const DistributedKv::Key &key)
338 {
339 KeepAliveInfo info;
340 nlohmann::json jsonObject = nlohmann::json::parse(key.ToString(), nullptr, false);
341 if (jsonObject.is_discarded()) {
342 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "parse jsonObject fail");
343 return info;
344 }
345
346 if (jsonObject.contains(JSON_KEY_BUNDLE_NAME) && jsonObject[JSON_KEY_BUNDLE_NAME].is_string()) {
347 info.bundleName = jsonObject.at(JSON_KEY_BUNDLE_NAME).get<std::string>();
348 }
349
350 if (jsonObject.contains(JSON_KEY_USERID) && jsonObject[JSON_KEY_USERID].is_number()) {
351 info.userId = jsonObject.at(JSON_KEY_USERID).get<int32_t>();
352 }
353
354 if (jsonObject.contains(JSON_KEY_APP_TYPE) && jsonObject[JSON_KEY_APP_TYPE].is_number()) {
355 info.appType = KeepAliveAppType(jsonObject.at(JSON_KEY_APP_TYPE).get<int32_t>());
356 }
357
358 if (jsonObject.contains(JSON_KEY_SETTER) && jsonObject[JSON_KEY_SETTER].is_number()) {
359 info.setter = KeepAliveSetter(jsonObject.at(JSON_KEY_SETTER).get<int32_t>());
360 }
361
362 return info;
363 }
364
IsEqual(const DistributedKv::Key & key,const KeepAliveInfo & info)365 bool AbilityKeepAliveDataManager::IsEqual(const DistributedKv::Key &key, const KeepAliveInfo &info)
366 {
367 nlohmann::json jsonObject = nlohmann::json::parse(key.ToString(), nullptr, false);
368 if (jsonObject.is_discarded()) {
369 TAG_LOGE(AAFwkTag::KEEP_ALIVE, "parse jsonObject fail");
370 return false;
371 }
372
373 if (!AAFwk::JsonUtils::GetInstance().IsEqual(jsonObject, JSON_KEY_USERID, info.userId)) {
374 return false;
375 }
376
377 if (!info.bundleName.empty() &&
378 !AAFwk::JsonUtils::GetInstance().IsEqual(jsonObject, JSON_KEY_BUNDLE_NAME, info.bundleName)) {
379 return false;
380 }
381
382 if (info.appType != KeepAliveAppType::UNSPECIFIED &&
383 !AAFwk::JsonUtils::GetInstance().IsEqual(jsonObject, JSON_KEY_APP_TYPE, static_cast<int32_t>(info.appType))) {
384 return false;
385 }
386
387 return true;
388 }
389 } // namespace AbilityRuntime
390 } // namespace OHOS
391