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