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