• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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_recovery.h"
17 
18 #include <sys/mman.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 
23 #include "ability_manager_client.h"
24 #include "app_recovery_parcel_allocator.h"
25 #include "context/application_context.h"
26 #include "file_ex.h"
27 #include "hilog_tag_wrapper.h"
28 #include "hitrace_meter.h"
29 #include "js_runtime.h"
30 #include "js_runtime_utils.h"
31 #include "napi/native_api.h"
32 #include "napi/native_common.h"
33 #include "parcel.h"
34 #include "recovery_param.h"
35 #include "string_ex.h"
36 #include "string_wrapper.h"
37 #include "want_params.h"
38 
39 namespace OHOS {
40 namespace AppExecFwk {
41 namespace {
42 constexpr size_t DEFAULT_RECOVERY_MAX_RESTORE_SIZE = 400 * 1024;
43 constexpr int32_t CALL_BACK_ERROR = -1;
44 
GetSaveAppCachePath(int32_t savedStateId)45 static std::string GetSaveAppCachePath(int32_t savedStateId)
46 {
47     auto context = AbilityRuntime::Context::GetApplicationContext();
48     if (context == nullptr) {
49         return "";
50     }
51 
52     std::string fileDir = context->GetFilesDir();
53     TAG_LOGD(AAFwkTag::RECOVERY, "fileDir %{public}s", fileDir.c_str());
54     if (fileDir.empty() || !OHOS::FileExists(fileDir)) {
55         TAG_LOGE(AAFwkTag::RECOVERY, "empty fileDir or fileDir not exist");
56         return "";
57     }
58 
59     std::string fileName = std::to_string(savedStateId) + ".state";
60     return fileDir + "/" + fileName;
61 }
62 }
63 
AbilityRecovery()64 AbilityRecovery::AbilityRecovery() : isEnable_(false), restartFlag_(RestartFlag::ALWAYS_RESTART),
65     saveOccasion_(SaveOccasionFlag::SAVE_WHEN_ERROR), saveMode_(SaveModeFlag::SAVE_WITH_FILE)
66 {
67 }
68 
~AbilityRecovery()69 AbilityRecovery::~AbilityRecovery()
70 {
71 }
72 
InitAbilityInfo(const std::shared_ptr<AbilityRuntime::UIAbility> ability,const std::shared_ptr<AbilityInfo> & abilityInfo,const sptr<IRemoteObject> & token)73 bool AbilityRecovery::InitAbilityInfo(const std::shared_ptr<AbilityRuntime::UIAbility> ability,
74     const std::shared_ptr<AbilityInfo>& abilityInfo, const sptr<IRemoteObject>& token)
75 {
76     isEnable_ = true;
77     ability_ = ability;
78     abilityInfo_ = abilityInfo;
79     token_ = token;
80     auto abilityContext = ability->GetAbilityContext();
81     if (abilityContext != nullptr) {
82         abilityContext->GetMissionId(missionId_);
83     }
84     return true;
85 }
86 
EnableAbilityRecovery(bool useAppSettedValue,uint16_t restartFlag,uint16_t saveFlag,uint16_t saveMode)87 void AbilityRecovery::EnableAbilityRecovery(bool useAppSettedValue, uint16_t restartFlag, uint16_t saveFlag,
88     uint16_t saveMode)
89 {
90     isEnable_ = true;
91     restartFlag_ = restartFlag;
92     useAppSettedValue_.store(useAppSettedValue);
93     saveOccasion_ = useAppSettedValue ? saveFlag : SaveOccasionFlag::SAVE_WHEN_BACKGROUND;
94     saveMode_ = saveMode;
95 }
96 
IsSameAbility(uintptr_t ability)97 bool AbilityRecovery::IsSameAbility(uintptr_t ability)
98 {
99     return ability == jsAbilityPtr_;
100 }
101 
SetJsAbility(uintptr_t ability)102 void AbilityRecovery::SetJsAbility(uintptr_t ability)
103 {
104     jsAbilityPtr_ = ability;
105 }
106 
SaveStateCallback(AppExecFwk::OnSaveStateResult result)107 void AbilityRecovery::SaveStateCallback(AppExecFwk::OnSaveStateResult result)
108 {
109     if (result.status != AppExecFwk::OnSaveResult::ALL_AGREE &&
110         result.status != AppExecFwk::OnSaveResult::RECOVERY_AGREE) {
111         TAG_LOGE(AAFwkTag::RECOVERY, "save params failed");
112         return;
113     }
114     auto ability = ability_.lock();
115     if (ability == nullptr) {
116         return;
117     }
118 #ifdef SUPPORT_SCREEN
119     std::string pageStack = DefaultRecovery() ? ability->GetContentInfoForDefaultRecovery() :
120         ability->GetContentInfoForRecovery();
121     if (!pageStack.empty()) {
122         result.wantParams.SetParam("pageStack", AAFwk::String::Box(pageStack));
123     } else {
124         TAG_LOGE(AAFwkTag::RECOVERY, "get page stack failed");
125     }
126     TAG_LOGD(AAFwkTag::RECOVERY, "pageStack size: %{public}zu", pageStack.size());
127 #endif
128     if (saveMode_ == SaveModeFlag::SAVE_WITH_FILE) {
129         SerializeDataToFile(missionId_, result.wantParams);
130     } else if (saveMode_ == SaveModeFlag::SAVE_WITH_SHARED_MEMORY) {
131         params_ = result.wantParams;
132     }
133     auto token = token_.promote();
134     if (token == nullptr) {
135         TAG_LOGE(AAFwkTag::RECOVERY, "null token");
136         return;
137     }
138     std::shared_ptr<AAFwk::AbilityManagerClient> abilityMgr = AAFwk::AbilityManagerClient::GetInstance();
139     if (abilityMgr == nullptr) {
140         TAG_LOGE(AAFwkTag::RECOVERY, "null abilityMgr");
141         return;
142     }
143     abilityMgr->EnableRecoverAbility(token);
144     if (result.reason == StateReason::LIFECYCLE && DefaultRecovery()) {
145         TAG_LOGD(AAFwkTag::RECOVERY, "AppRecovery ScheduleSaveAbilityState SubmitSaveRecoveryInfo");
146         abilityMgr->SubmitSaveRecoveryInfo(token);
147     }
148 }
149 
SaveAbilityState(StateReason reason)150 bool AbilityRecovery::SaveAbilityState(StateReason reason)
151 {
152     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
153     auto ability = ability_.lock();
154     auto abilityInfo = abilityInfo_.lock();
155     if (ability == nullptr || abilityInfo == nullptr) {
156         TAG_LOGE(AAFwkTag::RECOVERY, "null ability");
157         return false;
158     }
159 
160     auto *callbackInfo = AppExecFwk::AbilityTransactionCallbackInfo<AppExecFwk::OnSaveStateResult>::Create();
161     if (callbackInfo == nullptr) {
162         TAG_LOGE(AAFwkTag::APPKIT, "null callbackInfo");
163         return false;
164     }
165 
166     auto weak = std::weak_ptr<AbilityRecovery>(shared_from_this());
167     auto callback = [weak](AppExecFwk::OnSaveStateResult result) {
168         auto recovery = weak.lock();
169         if (recovery != nullptr) {
170             recovery->SaveStateCallback(result);
171         }
172     };
173     callbackInfo->Push(callback);
174     AAFwk::WantParams wantParams;
175     bool isAsync = false;
176     int32_t status = ability->OnSaveState(AppExecFwk::StateType::APP_RECOVERY,
177         wantParams, callbackInfo, isAsync, reason);
178     if (status == CALL_BACK_ERROR) {
179         AppExecFwk::AbilityTransactionCallbackInfo<AppExecFwk::OnSaveStateResult>::Destroy(callbackInfo);
180     }
181     return true;
182 }
183 
SerializeDataToFile(int32_t savedStateId,WantParams & params)184 bool AbilityRecovery::SerializeDataToFile(int32_t savedStateId, WantParams& params)
185 {
186     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
187     std::string file = GetSaveAppCachePath(savedStateId);
188     if (file.empty()) {
189         TAG_LOGE(AAFwkTag::RECOVERY, "persisted file path failed");
190         return false;
191     }
192     Parcel parcel;
193     if (!params.Marshalling(parcel)) {
194         TAG_LOGE(AAFwkTag::RECOVERY, "Marshalling want param failed");
195         return false;
196     }
197 
198     FILE *fileF = fopen(file.c_str(), "w+");
199     if (fileF == nullptr) {
200         TAG_LOGE(AAFwkTag::RECOVERY, "errno: %{public}d", errno);
201         return false;
202     }
203     size_t sz = parcel.GetDataSize();
204     uintptr_t buf = parcel.GetData();
205     if (sz == 0 || buf == 0) {
206         TAG_LOGE(AAFwkTag::RECOVERY, "get parcel data failed");
207         fclose(fileF);
208         return false;
209     }
210 
211     if (DefaultRecovery() && (sz > DEFAULT_RECOVERY_MAX_RESTORE_SIZE)) {
212         TAG_LOGE(AAFwkTag::RECOVERY, "data is too large, size: %{public}zu", sz);
213         fclose(fileF);
214         return false;
215     }
216 
217     size_t nwrite = fwrite(reinterpret_cast<uint8_t*>(buf), 1, sz, fileF);
218     if (nwrite != ERR_OK) {
219         TAG_LOGE(AAFwkTag::RECOVERY, "persist parcel data failed %{public}d", errno);
220     }
221     TAG_LOGD(AAFwkTag::RECOVERY, "file size: %{public}zu", sz);
222     fclose(fileF);
223     return true;
224 }
225 
ReadSerializeDataFromFile(int32_t savedStateId,WantParams & params)226 bool AbilityRecovery::ReadSerializeDataFromFile(int32_t savedStateId, WantParams& params)
227 {
228     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
229     std::string file = GetSaveAppCachePath(savedStateId);
230     if (file.empty()) {
231         TAG_LOGE(AAFwkTag::RECOVERY, "persisted file path failed");
232         return false;
233     }
234 
235     TAG_LOGD(AAFwkTag::RECOVERY, "file path %{public}s", file.c_str());
236     char path[PATH_MAX] = {0};
237     if (realpath(file.c_str(), path) == nullptr) {
238         TAG_LOGE(AAFwkTag::RECOVERY, "errno is %{public}d", errno);
239         return false;
240     }
241 
242     FILE *fileF = fopen(path, "r");
243     if (fileF == nullptr) {
244         TAG_LOGE(AAFwkTag::RECOVERY, "file open err: %{public}d", errno);
245         remove(path);
246         return false;
247     }
248     int fd = fileno(fileF);
249     struct stat statbuf;
250     if (fstat(fd, &statbuf) < 0) {
251         fclose(fileF);
252         remove(path);
253         return false;
254     }
255 
256     auto mapFile = static_cast<uint8_t*>(mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0));
257     if (mapFile == MAP_FAILED) {
258         fclose(fileF);
259         remove(path);
260         return false;
261     }
262 
263     Parcel parcel(new AppRecoveryParcelAllocator()); // do not dealloc mmap area
264     if (!parcel.ParseFrom(reinterpret_cast<uintptr_t>(mapFile), statbuf.st_size)) {
265         munmap(mapFile, statbuf.st_size);
266         fclose(fileF);
267         remove(path);
268         return false;
269     }
270 
271     auto parsedParam = WantParams::Unmarshalling(parcel);
272     if (parsedParam != nullptr) {
273         params = *parsedParam;
274         delete parsedParam;
275     } else {
276         munmap(mapFile, statbuf.st_size);
277         fclose(fileF);
278         remove(path);
279         return false;
280     }
281 
282     munmap(mapFile, statbuf.st_size);
283     fclose(fileF);
284     remove(path);
285     return true;
286 }
287 
ScheduleSaveAbilityState(StateReason reason)288 bool AbilityRecovery::ScheduleSaveAbilityState(StateReason reason)
289 {
290     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
291     if (!isEnable_) {
292         TAG_LOGE(AAFwkTag::RECOVERY, "not enable");
293         return false;
294     }
295 
296     if (missionId_ <= 0) {
297         TAG_LOGE(AAFwkTag::RECOVERY, "invalid missionId_");
298         return false;
299     }
300 
301     if (!IsSaveAbilityState(reason)) {
302         TAG_LOGE(AAFwkTag::RECOVERY, "not save ability state");
303         return false;
304     }
305 
306     return SaveAbilityState(reason);
307 }
308 
ScheduleRecoverAbility(StateReason reason,const Want * want)309 bool AbilityRecovery::ScheduleRecoverAbility(StateReason reason, const Want *want)
310 {
311     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
312     if (!isEnable_) {
313         TAG_LOGE(AAFwkTag::RECOVERY, "not enable");
314         return false;
315     }
316 
317     std::shared_ptr<AAFwk::AbilityManagerClient> abilityMgr = AAFwk::AbilityManagerClient::GetInstance();
318     if (abilityMgr == nullptr) {
319         TAG_LOGE(AAFwkTag::RECOVERY, "null abilityMgr");
320         return false;
321     }
322 
323     auto token = token_.promote();
324     if (token == nullptr) {
325         return false;
326     }
327     abilityMgr->ScheduleRecoverAbility(token, reason, want);
328     return true;
329 }
330 
PersistState()331 bool AbilityRecovery::PersistState()
332 {
333     auto abilityInfo = abilityInfo_.lock();
334     if (abilityInfo == nullptr) {
335         TAG_LOGE(AAFwkTag::RECOVERY, "null abilityInfo");
336         return false;
337     }
338     if (missionId_ <= 0) {
339         TAG_LOGE(AAFwkTag::RECOVERY, "invalid missionId");
340         return false;
341     }
342     if (!params_.IsEmpty()) {
343         SerializeDataToFile(missionId_, params_);
344     }
345     return true;
346 }
347 
IsOnForeground()348 bool AbilityRecovery::IsOnForeground()
349 {
350     auto ability = ability_.lock();
351     if (ability == nullptr) {
352         return false;
353     }
354     AbilityLifecycleExecutor::LifecycleState state = ability->GetState();
355     TAG_LOGI(AAFwkTag::RECOVERY, "state: %{public}d", state);
356     if (state == AbilityLifecycleExecutor::LifecycleState::FOREGROUND_NEW) {
357         return true;
358     }
359     return false;
360 }
361 
LoadSavedState(StateReason reason)362 bool AbilityRecovery::LoadSavedState(StateReason reason)
363 {
364     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
365     auto abilityInfo = abilityInfo_.lock();
366     if (abilityInfo == nullptr) {
367         TAG_LOGE(AAFwkTag::RECOVERY, "null abilityInfo");
368         return false;
369     }
370 
371     if (hasTryLoad_) {
372         return hasLoaded_;
373     }
374     if (missionId_ <= 0) {
375         TAG_LOGE(AAFwkTag::RECOVERY, "invalid missionId_");
376         return false;
377     }
378     hasTryLoad_ = true;
379 
380     TAG_LOGD(AAFwkTag::RECOVERY, "missionId_:%{public}d", missionId_);
381     if (!ReadSerializeDataFromFile(missionId_, params_)) {
382         TAG_LOGE(AAFwkTag::RECOVERY, "find record for id:%{public}d failed", missionId_);
383         hasLoaded_ = false;
384         return hasLoaded_;
385     }
386 
387     auto stringObj = AAFwk::IString::Query(params_.GetParam("pageStack"));
388     if (stringObj != nullptr) {
389         pageStack_ = AAFwk::String::Unbox(stringObj);
390     }
391     hasLoaded_ = true;
392     return hasLoaded_;
393 }
394 
ScheduleRestoreAbilityState(StateReason reason,const Want & want)395 bool AbilityRecovery::ScheduleRestoreAbilityState(StateReason reason, const Want &want)
396 {
397     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
398     if (!isEnable_) {
399         TAG_LOGE(AAFwkTag::RECOVERY, "not enable");
400         return false;
401     }
402 
403     if (!IsSaveAbilityState(reason)) {
404         TAG_LOGE(AAFwkTag::RECOVERY, "not save ability state");
405         return false;
406     }
407 
408     if (!LoadSavedState(reason)) {
409         TAG_LOGE(AAFwkTag::RECOVERY, "no saved state ");
410         return false;
411     }
412 
413     const WantParams &wantParams = want.GetParams();
414     WantParams &wantCurrent = const_cast<WantParams&>(wantParams);
415     for (auto& i : params_.GetParams()) {
416         wantCurrent.SetParam(i.first, i.second.GetRefPtr());
417     }
418     return true;
419 }
420 
GetSavedPageStack(StateReason reason)421 std::string AbilityRecovery::GetSavedPageStack(StateReason reason)
422 {
423     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
424     if (!LoadSavedState(reason)) {
425         TAG_LOGE(AAFwkTag::RECOVERY, "no saved state");
426         return "";
427     }
428 
429     if (pageStack_.empty()) {
430         TAG_LOGE(AAFwkTag::RECOVERY, "empty pageStack_");
431     }
432     return pageStack_;
433 }
434 
IsSaveAbilityState(StateReason reason)435 bool AbilityRecovery::IsSaveAbilityState(StateReason reason)
436 {
437     TAG_LOGD(AAFwkTag::RECOVERY, "enter");
438     bool ret = false;
439     switch (reason) {
440         case StateReason::DEVELOPER_REQUEST:
441             ret = true;
442             break;
443 
444         case StateReason::LIFECYCLE:
445             if ((saveOccasion_ & SaveOccasionFlag::SAVE_WHEN_BACKGROUND) != 0) {
446                 ret = true;
447             }
448             break;
449 
450         case StateReason::CPP_CRASH:
451         case StateReason::JS_ERROR:
452         case StateReason::CJ_ERROR:
453         case StateReason::APP_FREEZE:
454             if ((saveOccasion_ & SaveOccasionFlag::SAVE_WHEN_ERROR) != 0) {
455                 ret = true;
456             }
457             break;
458 
459         default:
460             ret = false;
461             break;
462     }
463     return ret;
464 }
465 
GetRestartFlag() const466 uint16_t AbilityRecovery::GetRestartFlag() const
467 {
468     return restartFlag_;
469 }
470 
GetSaveOccasionFlag() const471 uint16_t AbilityRecovery::GetSaveOccasionFlag() const
472 {
473     return saveOccasion_;
474 }
475 
GetSaveModeFlag() const476 uint16_t AbilityRecovery::GetSaveModeFlag() const
477 {
478     return saveMode_;
479 }
480 
DefaultRecovery() const481 bool AbilityRecovery::DefaultRecovery() const
482 {
483     return !(useAppSettedValue_.load());
484 }
485 }  // namespace AbilityRuntime
486 }  // namespace OHOS