• 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 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