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