• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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