1 /*
2  * Copyright (c) 2023-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 "app_exit_reason_data_manager.h"
17 
18 #include <cstdint>
19 
20 #include "accesstoken_kit.h"
21 #include "os_account_manager_wrapper.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 *APP_EXIT_REASON_STORAGE_DIR = "/data/service/el1/public/database/app_exit_reason";
29 const std::string JSON_KEY_REASON = "reason";
30 const std::string JSON_KEY_EXIT_MSG = "exit_msg";
31 const std::string JSON_KEY_TIME_STAMP = "time_stamp";
32 const std::string JSON_KEY_ABILITY_LIST = "ability_list";
33 const std::string KEY_RECOVER_INFO_PREFIX = "recover_info";
34 const std::string JSON_KEY_RECOVER_INFO_LIST = "recover_info_list";
35 const std::string JSON_KEY_SESSION_ID_LIST = "session_id_list";
36 const std::string JSON_KEY_EXTENSION_NAME = "extension_name";
37 const std::string SEPARATOR = ":";
38 } // namespace
AppExitReasonDataManager()39 AppExitReasonDataManager::AppExitReasonDataManager() {}
40 
~AppExitReasonDataManager()41 AppExitReasonDataManager::~AppExitReasonDataManager()
42 {
43     if (kvStorePtr_ != nullptr) {
44         dataManager_.CloseKvStore(appId_, kvStorePtr_);
45     }
46 }
47 
GetKvStore()48 DistributedKv::Status AppExitReasonDataManager::GetKvStore()
49 {
50     DistributedKv::Options options = { .createIfMissing = true,
51         .encrypt = false,
52         .autoSync = true,
53         .syncable = false,
54         .securityLevel = DistributedKv::SecurityLevel::S2,
55         .area = DistributedKv::EL1,
56         .kvStoreType = DistributedKv::KvStoreType::SINGLE_VERSION,
57         .baseDir = APP_EXIT_REASON_STORAGE_DIR };
58 
59     DistributedKv::Status status = dataManager_.GetSingleKvStore(options, appId_, storeId_, kvStorePtr_);
60     if (status != DistributedKv::Status::SUCCESS) {
61         TAG_LOGE(AAFwkTag::ABILITYMGR, "return error: %{public}d", status);
62     } else {
63         TAG_LOGI(AAFwkTag::ABILITYMGR, "get kvStore success");
64     }
65     return status;
66 }
67 
CheckKvStore()68 bool AppExitReasonDataManager::CheckKvStore()
69 {
70     TAG_LOGD(AAFwkTag::ABILITYMGR, "AppExitReasonDataManager::CheckKvStore start");
71     if (kvStorePtr_ != nullptr) {
72         return true;
73     }
74     int32_t tryTimes = MAX_TIMES;
75     while (tryTimes > 0) {
76         DistributedKv::Status status = GetKvStore();
77         if (status == DistributedKv::Status::SUCCESS && kvStorePtr_ != nullptr) {
78             return true;
79         }
80         TAG_LOGD(AAFwkTag::ABILITYMGR, "try times: %{public}d", tryTimes);
81         usleep(CHECK_INTERVAL);
82         tryTimes--;
83     }
84     return kvStorePtr_ != nullptr;
85 }
86 
SetAppExitReason(const std::string &bundleName, uint32_t accessTokenId, const std::vector<std::string> &abilityList, const AAFwk::ExitReason &exitReason)87 int32_t AppExitReasonDataManager::SetAppExitReason(const std::string &bundleName, uint32_t accessTokenId,
88     const std::vector<std::string> &abilityList, const AAFwk::ExitReason &exitReason)
89 {
90     auto accessTokenIdStr = std::to_string(accessTokenId);
91     if (bundleName.empty() || accessTokenId == Security::AccessToken::INVALID_TOKENID) {
92         TAG_LOGW(AAFwkTag::ABILITYMGR, "invalid value");
93         return ERR_INVALID_VALUE;
94     }
95 
96     TAG_LOGD(AAFwkTag::ABILITYMGR, "bundleName: %{public}s, tokenId: %{private}u", bundleName.c_str(), accessTokenId);
97     {
98         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
99         if (!CheckKvStore()) {
100             TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStore");
101             return ERR_NO_INIT;
102         }
103     }
104 
105     DistributedKv::Key key(accessTokenIdStr);
106     DistributedKv::Value value = ConvertAppExitReasonInfoToValue(abilityList, exitReason);
107     DistributedKv::Status status;
108     {
109         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
110         status = kvStorePtr_->Put(key, value);
111     }
112 
113     if (status != DistributedKv::Status::SUCCESS) {
114         TAG_LOGE(AAFwkTag::ABILITYMGR, "insert data err: %{public}d", status);
115         return ERR_INVALID_OPERATION;
116     }
117     return ERR_OK;
118 }
119 
120 
DeleteAppExitReason(const std::string &bundleName, int32_t uid, int32_t appIndex)121 int32_t AppExitReasonDataManager::DeleteAppExitReason(const std::string &bundleName, int32_t uid, int32_t appIndex)
122 {
123     int32_t userId;
124     if (DelayedSingleton<AppExecFwk::OsAccountManagerWrapper>::GetInstance()->
125         GetOsAccountLocalIdFromUid(uid, userId) != ERR_OK) {
126         TAG_LOGE(AAFwkTag::ABILITYMGR, "get GetOsAccountLocalIdFromUid failed");
127         return ERR_INVALID_VALUE;
128     }
129     uint32_t accessTokenId = Security::AccessToken::AccessTokenKit::GetHapTokenID(userId, bundleName, appIndex);
130     return DeleteAppExitReason(bundleName, accessTokenId);
131 }
132 
DeleteAppExitReason(const std::string &bundleName, uint32_t accessTokenId)133 int32_t AppExitReasonDataManager::DeleteAppExitReason(const std::string &bundleName, uint32_t accessTokenId)
134 {
135     auto accessTokenIdStr = std::to_string(accessTokenId);
136     if (bundleName.empty() || accessTokenId == Security::AccessToken::INVALID_TOKENID) {
137         TAG_LOGW(AAFwkTag::ABILITYMGR, "invalid value");
138         return ERR_INVALID_VALUE;
139     }
140 
141     TAG_LOGD(AAFwkTag::ABILITYMGR, "bundleName: %{public}s, tokenId: %{private}u", bundleName.c_str(), accessTokenId);
142     {
143         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
144         if (!CheckKvStore()) {
145             TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStore");
146             return ERR_NO_INIT;
147         }
148     }
149 
150     std::string keyUiExten = bundleName + SEPARATOR;
151     std::vector<DistributedKv::Entry> allEntries;
152     DistributedKv::Status status = kvStorePtr_->GetEntries(nullptr, allEntries);
153     if (status != DistributedKv::Status::SUCCESS) {
154         TAG_LOGE(AAFwkTag::ABILITYMGR, "error: %{public}d", status);
155         return ERR_INVALID_OPERATION;
156     }
157 
158     for (const auto &item : allEntries) {
159         const auto &keyValue = item.key.ToString();
160         if (keyValue != accessTokenIdStr && keyValue.find(keyUiExten) == std::string::npos) {
161             continue;
162         }
163 
164         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
165         auto errCode = kvStorePtr_->Delete(item.key);
166         status = (errCode != DistributedKv::Status::SUCCESS) ? errCode : status;
167     }
168 
169     if (status != DistributedKv::Status::SUCCESS) {
170         TAG_LOGE(AAFwkTag::ABILITYMGR, "error: %{public}d", status);
171         return ERR_INVALID_OPERATION;
172     }
173     return ERR_OK;
174 }
175 
GetAppExitReason(const std::string &bundleName, uint32_t accessTokenId, const std::string &abilityName, bool &isSetReason, AAFwk::ExitReason &exitReason)176 int32_t AppExitReasonDataManager::GetAppExitReason(const std::string &bundleName, uint32_t accessTokenId,
177     const std::string &abilityName, bool &isSetReason, AAFwk::ExitReason &exitReason)
178 {
179     auto accessTokenIdStr = std::to_string(accessTokenId);
180     if (bundleName.empty() || accessTokenId == Security::AccessToken::INVALID_TOKENID) {
181         TAG_LOGW(AAFwkTag::ABILITYMGR, "invalid value");
182         return ERR_INVALID_VALUE;
183     }
184     TAG_LOGD(AAFwkTag::ABILITYMGR, "bundleName: %{public}s, tokenId: %{private}u, abilityName: %{public}s.",
185         bundleName.c_str(), accessTokenId, abilityName.c_str());
186     {
187         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
188         if (!CheckKvStore()) {
189             TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStore");
190             return ERR_NO_INIT;
191         }
192     }
193 
194     std::vector<DistributedKv::Entry> allEntries;
195     DistributedKv::Status status = kvStorePtr_->GetEntries(nullptr, allEntries);
196     if (status != DistributedKv::Status::SUCCESS) {
197         TAG_LOGE(AAFwkTag::ABILITYMGR, "get entries error: %{public}d", status);
198         return ERR_INVALID_VALUE;
199     }
200 
201     std::vector<std::string> abilityList;
202     int64_t time_stamp;
203     isSetReason = false;
204     for (const auto &item : allEntries) {
205         if (item.key.ToString() == accessTokenIdStr) {
206             ConvertAppExitReasonInfoFromValue(item.value, exitReason, time_stamp, abilityList);
207             auto pos = std::find(abilityList.begin(), abilityList.end(), abilityName);
208             if (pos != abilityList.end()) {
209                 isSetReason = true;
210                 abilityList.erase(std::remove(abilityList.begin(), abilityList.end(), abilityName), abilityList.end());
211                 UpdateAppExitReason(accessTokenId, abilityList, exitReason);
212             }
213             TAG_LOGI(AAFwkTag::ABILITYMGR, "current bundle name: %{public}s, tokenId:%{private}u, reason: %{public}d,"
214                 "  exitMsg: %{public}s, abilityName:%{public}s isSetReason:%{public}d",
215                 bundleName.c_str(), accessTokenId, exitReason.reason, exitReason.exitMsg.c_str(),
216                 abilityName.c_str(), isSetReason);
217             if (abilityList.empty()) {
218                 InnerDeleteAppExitReason(accessTokenIdStr);
219             }
220             break;
221         }
222     }
223 
224     return ERR_OK;
225 }
226 
UpdateAppExitReason(uint32_t accessTokenId, const std::vector<std::string> &abilityList, const AAFwk::ExitReason &exitReason)227 void AppExitReasonDataManager::UpdateAppExitReason(uint32_t accessTokenId, const std::vector<std::string> &abilityList,
228     const AAFwk::ExitReason &exitReason)
229 {
230     if (kvStorePtr_ == nullptr) {
231         TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStorePtr_");
232         return;
233     }
234 
235     DistributedKv::Key key(std::to_string(accessTokenId));
236     DistributedKv::Status status;
237     {
238         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
239         status = kvStorePtr_->Delete(key);
240     }
241     if (status != DistributedKv::Status::SUCCESS) {
242         TAG_LOGE(AAFwkTag::ABILITYMGR, "error: %{public}d", status);
243         return;
244     }
245 
246     DistributedKv::Value value = ConvertAppExitReasonInfoToValue(abilityList, exitReason);
247     {
248         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
249         status = kvStorePtr_->Put(key, value);
250     }
251     if (status != DistributedKv::Status::SUCCESS) {
252         TAG_LOGE(AAFwkTag::ABILITYMGR, "error: %{public}d", status);
253     }
254 }
255 
ConvertAppExitReasonInfoToValue( const std::vector<std::string> &abilityList, const AAFwk::ExitReason &exitReason)256 DistributedKv::Value AppExitReasonDataManager::ConvertAppExitReasonInfoToValue(
257     const std::vector<std::string> &abilityList, const AAFwk::ExitReason &exitReason)
258 {
259     std::chrono::milliseconds nowMs =
260         std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
261     nlohmann::json jsonObject = nlohmann::json {
262         { JSON_KEY_REASON, exitReason.reason },
263         { JSON_KEY_EXIT_MSG, exitReason.exitMsg },
264         { JSON_KEY_TIME_STAMP, nowMs.count() },
265         { JSON_KEY_ABILITY_LIST, abilityList },
266     };
267     DistributedKv::Value value(jsonObject.dump());
268     TAG_LOGI(AAFwkTag::ABILITYMGR, "value: %{public}s", value.ToString().c_str());
269     return value;
270 }
271 
ConvertAppExitReasonInfoFromValue(const DistributedKv::Value &value, AAFwk::ExitReason &exitReason, int64_t &time_stamp, std::vector<std::string> &abilityList)272 void AppExitReasonDataManager::ConvertAppExitReasonInfoFromValue(const DistributedKv::Value &value,
273     AAFwk::ExitReason &exitReason, int64_t &time_stamp, std::vector<std::string> &abilityList)
274 {
275     nlohmann::json jsonObject = nlohmann::json::parse(value.ToString(), nullptr, false);
276     if (jsonObject.is_discarded()) {
277         TAG_LOGE(AAFwkTag::ABILITYMGR, "parse json sting failed");
278         return;
279     }
280     if (jsonObject.contains(JSON_KEY_REASON) && jsonObject[JSON_KEY_REASON].is_number_integer()) {
281         exitReason.reason = jsonObject.at(JSON_KEY_REASON).get<AAFwk::Reason>();
282     }
283     if (jsonObject.contains(JSON_KEY_EXIT_MSG) && jsonObject[JSON_KEY_EXIT_MSG].is_string()) {
284         exitReason.exitMsg = jsonObject.at(JSON_KEY_EXIT_MSG).get<std::string>();
285     }
286     if (jsonObject.contains(JSON_KEY_TIME_STAMP) && jsonObject[JSON_KEY_TIME_STAMP].is_number_integer()) {
287         time_stamp = jsonObject.at(JSON_KEY_TIME_STAMP).get<int64_t>();
288     }
289     if (jsonObject.contains(JSON_KEY_ABILITY_LIST) && jsonObject[JSON_KEY_ABILITY_LIST].is_array()) {
290         abilityList.clear();
291         auto size = jsonObject[JSON_KEY_ABILITY_LIST].size();
292         for (size_t i = 0; i < size; i++) {
293             if (jsonObject[JSON_KEY_ABILITY_LIST][i].is_string()) {
294                 abilityList.emplace_back(jsonObject[JSON_KEY_ABILITY_LIST][i]);
295             }
296         }
297     }
298 }
299 
InnerDeleteAppExitReason(const std::string &keyName)300 void AppExitReasonDataManager::InnerDeleteAppExitReason(const std::string &keyName)
301 {
302     if (kvStorePtr_ == nullptr) {
303         TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStorePtr_");
304         return;
305     }
306 
307     DistributedKv::Key key(keyName);
308     DistributedKv::Status status;
309     {
310         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
311         status = kvStorePtr_->Delete(key);
312     }
313 
314     if (status != DistributedKv::Status::SUCCESS) {
315         TAG_LOGE(AAFwkTag::ABILITYMGR, "error: %{public}d", status);
316     }
317 }
318 
AddAbilityRecoverInfo(uint32_t accessTokenId, const std::string &moduleName, const std::string &abilityName, const int &sessionId)319 int32_t AppExitReasonDataManager::AddAbilityRecoverInfo(uint32_t accessTokenId,
320     const std::string &moduleName, const std::string &abilityName, const int &sessionId)
321 {
322     TAG_LOGI(AAFwkTag::ABILITYMGR,
323         "AddAbilityRecoverInfo tokenId %{private}u module %{public}s ability %{public}s id %{public}d ",
324         accessTokenId, moduleName.c_str(), abilityName.c_str(), sessionId);
325     {
326         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
327         if (!CheckKvStore()) {
328             TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStore");
329             return ERR_NO_INIT;
330         }
331     }
332 
333     DistributedKv::Key key = GetAbilityRecoverInfoKey(accessTokenId);
334     DistributedKv::Value value;
335     DistributedKv::Status status = kvStorePtr_->Get(key, value);
336     if (status != DistributedKv::Status::SUCCESS && status != DistributedKv::Status::KEY_NOT_FOUND) {
337         TAG_LOGE(AAFwkTag::ABILITYMGR, "AddAbilityRecoverInfo get error: %{public}d", status);
338         return ERR_INVALID_VALUE;
339     }
340 
341     std::vector<std::string> recoverInfoList;
342     std::vector<int> sessionIdList;
343     std::string recoverInfo = moduleName + abilityName;
344     if (status == DistributedKv::Status::SUCCESS) {
345         ConvertAbilityRecoverInfoFromValue(value, recoverInfoList, sessionIdList);
346         auto pos = std::find(recoverInfoList.begin(), recoverInfoList.end(), recoverInfo);
347         if (pos != recoverInfoList.end()) {
348             TAG_LOGW(AAFwkTag::ABILITYMGR, "AddAbilityRecoverInfo recoverInfo already record");
349             int index = std::distance(recoverInfoList.begin(), pos);
350             sessionIdList[index] = sessionId;
351             return ERR_OK;
352         }
353     }
354 
355     recoverInfoList.emplace_back(recoverInfo);
356     sessionIdList.emplace_back(sessionId);
357     value = ConvertAbilityRecoverInfoToValue(recoverInfoList, sessionIdList);
358     {
359         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
360         status = kvStorePtr_->Put(key, value);
361     }
362 
363     if (status != DistributedKv::Status::SUCCESS) {
364         TAG_LOGE(AAFwkTag::ABILITYMGR, "error : %{public}d", status);
365         return ERR_INVALID_OPERATION;
366     }
367 
368     TAG_LOGI(AAFwkTag::ABILITYMGR, "AddAbilityRecoverInfo finish");
369     return ERR_OK;
370 }
371 
DeleteAllRecoverInfoByTokenId(uint32_t tokenId)372 int32_t AppExitReasonDataManager::DeleteAllRecoverInfoByTokenId(uint32_t tokenId)
373 {
374     TAG_LOGI(AAFwkTag::ABILITYMGR, "tokenId: %{private}u", tokenId);
375     {
376         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
377         if (!CheckKvStore()) {
378             TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStore");
379             return ERR_NO_INIT;
380         }
381     }
382     InnerDeleteAbilityRecoverInfo(tokenId);
383     return ERR_OK;
384 }
385 
DeleteAbilityRecoverInfo( uint32_t accessTokenId, const std::string &moduleName, const std::string &abilityName)386 int32_t AppExitReasonDataManager::DeleteAbilityRecoverInfo(
387     uint32_t accessTokenId, const std::string &moduleName, const std::string &abilityName)
388 {
389     TAG_LOGI(AAFwkTag::ABILITYMGR, "tokenId %{private}u module %{public}s ability %{public}s ",
390         accessTokenId, moduleName.c_str(), abilityName.c_str());
391     {
392         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
393         if (!CheckKvStore()) {
394             TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStore");
395             return ERR_NO_INIT;
396         }
397     }
398 
399     DistributedKv::Key key = GetAbilityRecoverInfoKey(accessTokenId);
400     DistributedKv::Value value;
401     DistributedKv::Status status = kvStorePtr_->Get(key, value);
402     if (status != DistributedKv::Status::SUCCESS) {
403         TAG_LOGE(AAFwkTag::ABILITYMGR, "failed:%{public}d", status);
404         return ERR_INVALID_VALUE;
405     }
406 
407     std::vector<std::string> recoverInfoList;
408     std::vector<int> sessionIdList;
409     std::string recoverInfo = moduleName + abilityName;
410     ConvertAbilityRecoverInfoFromValue(value, recoverInfoList, sessionIdList);
411     auto pos = std::find(recoverInfoList.begin(), recoverInfoList.end(), recoverInfo);
412     if (pos != recoverInfoList.end()) {
413         recoverInfoList.erase(std::remove(recoverInfoList.begin(), recoverInfoList.end(), recoverInfo),
414             recoverInfoList.end());
415         int index = std::distance(recoverInfoList.begin(), pos);
416         sessionIdList.erase(std::remove(sessionIdList.begin(), sessionIdList.end(), sessionIdList[index]),
417             sessionIdList.end());
418         UpdateAbilityRecoverInfo(accessTokenId, recoverInfoList, sessionIdList);
419         TAG_LOGI(AAFwkTag::ABILITYMGR, "DeleteAbilityRecoverInfo remove recoverInfo succeed");
420     }
421     if (recoverInfoList.empty()) {
422         InnerDeleteAbilityRecoverInfo(accessTokenId);
423     }
424 
425     TAG_LOGI(AAFwkTag::ABILITYMGR, "DeleteAbilityRecoverInfo finished");
426     return ERR_OK;
427 }
428 
GetAbilityRecoverInfo( uint32_t accessTokenId, const std::string &moduleName, const std::string &abilityName, bool &hasRecoverInfo)429 int32_t AppExitReasonDataManager::GetAbilityRecoverInfo(
430     uint32_t accessTokenId, const std::string &moduleName, const std::string &abilityName, bool &hasRecoverInfo)
431 {
432     TAG_LOGI(AAFwkTag::ABILITYMGR, "tokenId %{private}u module %{public}s abillity %{public}s",
433         accessTokenId, moduleName.c_str(), abilityName.c_str());
434     hasRecoverInfo = false;
435     {
436         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
437         if (!CheckKvStore()) {
438             TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStore");
439             return ERR_NO_INIT;
440         }
441     }
442 
443     DistributedKv::Key key = GetAbilityRecoverInfoKey(accessTokenId);
444     DistributedKv::Value value;
445     DistributedKv::Status status = kvStorePtr_->Get(key, value);
446     if (status != DistributedKv::Status::SUCCESS) {
447         if (status == DistributedKv::Status::KEY_NOT_FOUND) {
448             TAG_LOGW(AAFwkTag::ABILITYMGR, "KEY_NOT_FOUND");
449         } else {
450             TAG_LOGE(AAFwkTag::ABILITYMGR, "error:%{public}d", status);
451         }
452         return ERR_INVALID_VALUE;
453     }
454 
455     std::vector<std::string> recoverInfoList;
456     std::vector<int> sessionIdList;
457     std::string recoverInfo = moduleName + abilityName;
458     ConvertAbilityRecoverInfoFromValue(value, recoverInfoList, sessionIdList);
459     auto pos = std::find(recoverInfoList.begin(), recoverInfoList.end(), recoverInfo);
460     if (pos != recoverInfoList.end()) {
461         hasRecoverInfo = true;
462         TAG_LOGI(AAFwkTag::ABILITYMGR, "GetAbilityRecoverInfo hasRecoverInfo found info");
463     }
464     return ERR_OK;
465 }
466 
SetUIExtensionAbilityExitReason( const std::string &bundleName, const std::vector<std::string> &extensionList, const AAFwk::ExitReason &exitReason)467 int32_t AppExitReasonDataManager::SetUIExtensionAbilityExitReason(
468     const std::string &bundleName, const std::vector<std::string> &extensionList, const AAFwk::ExitReason &exitReason)
469 {
470     TAG_LOGD(AAFwkTag::ABILITYMGR, "called");
471     if (bundleName.empty()) {
472         TAG_LOGW(AAFwkTag::ABILITYMGR, "invalid bundle name");
473         return ERR_INVALID_VALUE;
474     }
475 
476     {
477         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
478         if (!CheckKvStore()) {
479             TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStorePtr_");
480             return ERR_NO_INIT;
481         }
482     }
483 
484     for (const auto &extension : extensionList) {
485         std::string keyEx = bundleName + SEPARATOR + extension;
486         DistributedKv::Key key(keyEx);
487         DistributedKv::Value value = ConvertAppExitReasonInfoToValueOfExtensionName(extension, exitReason);
488         DistributedKv::Status status;
489         {
490             std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
491             status = kvStorePtr_->Put(key, value);
492         }
493 
494         if (status != DistributedKv::Status::SUCCESS) {
495             TAG_LOGW(AAFwkTag::ABILITYMGR, "error: %{public}d", status);
496         }
497     }
498 
499     return ERR_OK;
500 }
501 
GetUIExtensionAbilityExitReason(const std::string &keyEx, AAFwk::ExitReason &exitReason)502 bool AppExitReasonDataManager::GetUIExtensionAbilityExitReason(const std::string &keyEx,
503     AAFwk::ExitReason &exitReason)
504 {
505     TAG_LOGD(AAFwkTag::ABILITYMGR, "called");
506     {
507         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
508         if (!CheckKvStore()) {
509             TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStorePtr_");
510             return false;
511         }
512     }
513 
514     std::vector<DistributedKv::Entry> allEntries;
515     DistributedKv::Status status = kvStorePtr_->GetEntries(nullptr, allEntries);
516     if (status != DistributedKv::Status::SUCCESS) {
517         TAG_LOGE(AAFwkTag::ABILITYMGR, "error: %{public}d", status);
518         return false;
519     }
520     std::vector<std::string> abilityList;
521     int64_t time_stamp;
522     bool isHaveReason = false;
523     for (const auto &item : allEntries) {
524         if (item.key.ToString() == keyEx) {
525             ConvertAppExitReasonInfoFromValue(item.value, exitReason, time_stamp, abilityList);
526             isHaveReason = true;
527             InnerDeleteAppExitReason(keyEx);
528             break;
529         }
530     }
531 
532     return isHaveReason;
533 }
534 
UpdateAbilityRecoverInfo(uint32_t accessTokenId, const std::vector<std::string> &recoverInfoList, const std::vector<int> &sessionIdList)535 void AppExitReasonDataManager::UpdateAbilityRecoverInfo(uint32_t accessTokenId,
536     const std::vector<std::string> &recoverInfoList, const std::vector<int> &sessionIdList)
537 {
538     if (kvStorePtr_ == nullptr) {
539         TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStorePtr_");
540         return;
541     }
542 
543     DistributedKv::Key key = GetAbilityRecoverInfoKey(accessTokenId);
544     DistributedKv::Status status;
545     {
546         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
547         status = kvStorePtr_->Delete(key);
548     }
549     if (status != DistributedKv::Status::SUCCESS) {
550         TAG_LOGE(AAFwkTag::ABILITYMGR, "error: %{public}d", status);
551         return;
552     }
553 
554     DistributedKv::Value value = ConvertAbilityRecoverInfoToValue(recoverInfoList, sessionIdList);
555     {
556         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
557         status = kvStorePtr_->Put(key, value);
558     }
559     if (status != DistributedKv::Status::SUCCESS) {
560         TAG_LOGE(AAFwkTag::ABILITYMGR, "failed: %{public}d", status);
561     }
562 }
563 
ConvertAbilityRecoverInfoToValue( const std::vector<std::string> &recoverInfoList, const std::vector<int> &sessionIdList)564 DistributedKv::Value AppExitReasonDataManager::ConvertAbilityRecoverInfoToValue(
565     const std::vector<std::string> &recoverInfoList, const std::vector<int> &sessionIdList)
566 {
567     nlohmann::json jsonObject = nlohmann::json {
568         { JSON_KEY_RECOVER_INFO_LIST, recoverInfoList },
569         { JSON_KEY_SESSION_ID_LIST, sessionIdList },
570     };
571     DistributedKv::Value value(jsonObject.dump());
572     TAG_LOGI(AAFwkTag::ABILITYMGR, "ConvertAbilityRecoverInfoToValue value: %{public}s", value.ToString().c_str());
573     return value;
574 }
575 
ConvertAbilityRecoverInfoFromValue(const DistributedKv::Value &value, std::vector<std::string> &recoverInfoList, std::vector<int> &sessionIdList)576 void AppExitReasonDataManager::ConvertAbilityRecoverInfoFromValue(const DistributedKv::Value &value,
577     std::vector<std::string> &recoverInfoList, std::vector<int> &sessionIdList)
578 {
579     nlohmann::json jsonObject = nlohmann::json::parse(value.ToString(), nullptr, false);
580     if (jsonObject.is_discarded()) {
581         TAG_LOGE(AAFwkTag::ABILITYMGR, "parse json sting failed");
582         return;
583     }
584     if (jsonObject.contains(JSON_KEY_RECOVER_INFO_LIST)
585         && jsonObject[JSON_KEY_RECOVER_INFO_LIST].is_array()) {
586         recoverInfoList.clear();
587         auto size = jsonObject[JSON_KEY_RECOVER_INFO_LIST].size();
588         for (size_t i = 0; i < size; i++) {
589             if (jsonObject[JSON_KEY_RECOVER_INFO_LIST][i].is_string()) {
590                 recoverInfoList.emplace_back(jsonObject[JSON_KEY_RECOVER_INFO_LIST][i]);
591             }
592         }
593     }
594     if (jsonObject.contains(JSON_KEY_SESSION_ID_LIST)
595         && jsonObject[JSON_KEY_SESSION_ID_LIST].is_array()) {
596         sessionIdList.clear();
597         auto size = jsonObject[JSON_KEY_SESSION_ID_LIST].size();
598         for (size_t i = 0; i < size; i++) {
599             if (jsonObject[JSON_KEY_SESSION_ID_LIST][i].is_number_integer()) {
600                 sessionIdList.emplace_back(jsonObject[JSON_KEY_SESSION_ID_LIST][i]);
601             }
602         }
603     }
604 }
605 
InnerDeleteAbilityRecoverInfo(uint32_t accessTokenId)606 void AppExitReasonDataManager::InnerDeleteAbilityRecoverInfo(uint32_t accessTokenId)
607 {
608     if (kvStorePtr_ == nullptr) {
609         TAG_LOGE(AAFwkTag::ABILITYMGR, "null kvStorePtr_");
610         return;
611     }
612 
613     DistributedKv::Key key = GetAbilityRecoverInfoKey(accessTokenId);
614     DistributedKv::Status status;
615     {
616         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
617         status = kvStorePtr_->Delete(key);
618     }
619 
620     if (status != DistributedKv::Status::SUCCESS) {
621         TAG_LOGE(AAFwkTag::ABILITYMGR, "error: %{public}d", status);
622     }
623 }
624 
GetAbilityRecoverInfoKey(uint32_t accessTokenId)625 DistributedKv::Key AppExitReasonDataManager::GetAbilityRecoverInfoKey(uint32_t accessTokenId)
626 {
627     return DistributedKv::Key(KEY_RECOVER_INFO_PREFIX + std::to_string(accessTokenId));
628 }
629 
ConvertAppExitReasonInfoToValueOfExtensionName( const std::string &extensionListName, const AAFwk::ExitReason &exitReason)630 DistributedKv::Value AppExitReasonDataManager::ConvertAppExitReasonInfoToValueOfExtensionName(
631     const std::string &extensionListName, const AAFwk::ExitReason &exitReason)
632 {
633     TAG_LOGD(AAFwkTag::ABILITYMGR, "called");
634     std::chrono::milliseconds nowMs =
635         std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
636     nlohmann::json jsonObject = nlohmann::json {
637         { JSON_KEY_REASON, exitReason.reason },
638         { JSON_KEY_EXIT_MSG, exitReason.exitMsg },
639         { JSON_KEY_TIME_STAMP, nowMs.count() },
640         { JSON_KEY_EXTENSION_NAME, extensionListName },
641     };
642     DistributedKv::Value value(jsonObject.dump());
643     return value;
644 }
645 } // namespace AbilityRuntime
646 } // namespace OHOS
647