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