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