• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "app_recovery.h"
17 
18 #include <csignal>
19 #include <mutex>
20 
21 #include <sys/mman.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 
25 #include <syscall.h>
26 #include <unistd.h>
27 
28 #include "ability_runtime/js_ability.h"
29 #include "js_runtime.h"
30 #include "js_runtime_utils.h"
31 #include "mission_info.h"
32 #include "napi/native_api.h"
33 #include "napi/native_common.h"
34 
35 #include "ability_manager_client.h"
36 
37 #include "directory_ex.h"
38 #include "file_ex.h"
39 #include "hilog_wrapper.h"
40 #include "parcel.h"
41 #include "want_params.h"
42 #include "recovery_param.h"
43 #include "string_ex.h"
44 #include "string_wrapper.h"
45 #include "ohos_application.h"
46 
47 namespace OHOS {
48 namespace AppExecFwk {
49 std::mutex g_mutex;
50 std::atomic<bool> g_blocked = false;
51 const int DELAY_TIME = 1000;
52 
AppRecovery()53 AppRecovery::AppRecovery() : isEnable_(false), restartFlag_(RestartFlag::ALWAYS_RESTART),
54     saveOccasion_(SaveOccasionFlag::SAVE_WHEN_ERROR), saveMode_(SaveModeFlag::SAVE_WITH_FILE)
55 {
56 }
57 
~AppRecovery()58 AppRecovery::~AppRecovery()
59 {
60 }
61 
SigQuitHandler(int signal)62 static void SigQuitHandler(int signal)
63 {
64     g_blocked = true;
65     std::lock_guard<std::mutex> lock(g_mutex);
66     g_blocked = false;
67 }
68 
BlockMainThreadLocked()69 static bool BlockMainThreadLocked()
70 {
71     struct sigaction action;
72     (void)memset_s(&action, sizeof(action), 0, sizeof(action));
73     sigfillset(&action.sa_mask);
74     action.sa_handler = SigQuitHandler;
75     action.sa_flags = 0;
76     if (sigaction(SIGQUIT, &action, nullptr) != 0) {
77         HILOG_ERROR("AppRecovery Failed to register signal");
78         return false;
79     }
80 
81     if (syscall(SYS_tgkill, getpid(), getpid(), SIGQUIT) != 0) {
82         HILOG_ERROR("Failed to send SIGQUIT to main thread, errno(%d).", errno);
83         return false;
84     }
85     int left = 1000000; // 1s
86     constexpr int pollTime = 100; // 100us
87     while (left > 0) {
88         int ret = usleep(pollTime);
89         if (ret == 0) {
90             left -= pollTime;
91         } else {
92             left -= ret;
93         }
94 
95         if (g_blocked) {
96             return true;
97         }
98     }
99     return false;
100 }
101 
GetInstance()102 AppRecovery& AppRecovery::GetInstance()
103 {
104     static AppRecovery instance;
105     return instance;
106 }
107 
InitApplicationInfo(const std::shared_ptr<EventHandler> & mainHandler,const std::shared_ptr<ApplicationInfo> & applicationInfo)108 bool AppRecovery::InitApplicationInfo(const std::shared_ptr<EventHandler>& mainHandler,
109     const std::shared_ptr<ApplicationInfo>& applicationInfo)
110 {
111     mainHandler_ = mainHandler;
112     applicationInfo_ = applicationInfo;
113     return true;
114 }
115 
AddAbility(std::shared_ptr<Ability> ability,const std::shared_ptr<AbilityInfo> & abilityInfo,const sptr<IRemoteObject> & token)116 bool AppRecovery::AddAbility(std::shared_ptr<Ability> ability,
117     const std::shared_ptr<AbilityInfo>& abilityInfo, const sptr<IRemoteObject>& token)
118 {
119     if (!isEnable_) {
120         HILOG_ERROR("AppRecovery not enabled.");
121         return false;
122     }
123 
124     if (!abilityRecoverys_.empty() && !abilityInfo->recoverable) {
125         HILOG_ERROR("AppRecovery abilityRecoverys is not empty but ability recoverable is false.");
126         return false;
127     }
128     ability_ = ability;
129     std::shared_ptr<AbilityRecovery> abilityRecovery = std::make_shared<AbilityRecovery>();
130     abilityRecovery->InitAbilityInfo(ability, abilityInfo, token);
131     abilityRecovery->EnableAbilityRecovery(restartFlag_, saveOccasion_, saveMode_);
132     ability->EnableAbilityRecovery(abilityRecovery);
133     abilityRecoverys_.push_back(abilityRecovery);
134     auto handler = mainHandler_.lock();
135     if (handler != nullptr) {
136         auto task = []() {
137             AppRecovery::GetInstance().DeleteInValidMissionFiles();
138         };
139         if (!handler->PostTask(task, DELAY_TIME)) {
140             HILOG_ERROR("Failed to DeleteInValidMissionFiles.");
141         }
142     }
143     return true;
144 }
145 
RemoveAbility(const sptr<IRemoteObject> & tokenId)146 bool AppRecovery::RemoveAbility(const sptr<IRemoteObject>& tokenId)
147 {
148     if (!isEnable_) {
149         HILOG_ERROR("AppRecovery not enabled. not removeAbility");
150         return false;
151     }
152 
153     if (!tokenId) {
154         HILOG_ERROR("AppRecovery removeAbility tokenId is null.");
155         return false;
156     }
157     HILOG_DEBUG("AppRecovery removeAbility start");
158     auto itr = std::find_if(abilityRecoverys_.begin(), abilityRecoverys_.end(),
159         [&tokenId](std::shared_ptr<AbilityRecovery> &abilityRecovery) {
160         return (abilityRecovery && abilityRecovery->GetToken() == tokenId);
161     });
162     if (itr != abilityRecoverys_.end()) {
163         abilityRecoverys_.erase(itr);
164         HILOG_DEBUG("AppRecovery removeAbility done");
165     }
166     return true;
167 }
168 
ScheduleSaveAppState(StateReason reason,uintptr_t ability)169 bool AppRecovery::ScheduleSaveAppState(StateReason reason, uintptr_t ability)
170 {
171     HILOG_DEBUG("AppRecovery ScheduleSaveAppState begin");
172     if (!isEnable_) {
173         HILOG_ERROR("AppRecovery ScheduleSaveAppState. is not enabled");
174         return false;
175     }
176 
177     if (!ShouldSaveAppState(reason)) {
178         HILOG_ERROR("AppRecovery ts not save ability state");
179         return false;
180     }
181 
182     if (reason == StateReason::APP_FREEZE) {
183         auto abilityPtr = ability_.lock();
184         if (!abilityPtr || !abilityPtr->GetAbilityContext()) {
185             HILOG_ERROR("AppRecovery ScheduleSaveAppState ability or context is nullptr");
186             return false;
187         }
188         std::lock_guard<std::mutex> lock(g_mutex);
189         if (!BlockMainThreadLocked()) {
190             HILOG_ERROR("AppRecovery Failed to block main thread, skip save state when appfreeze");
191             return false;
192         }
193         OHOS::AbilityRuntime::JsAbility& jsAbility = static_cast<AbilityRuntime::JsAbility&>(*abilityPtr);
194         AbilityRuntime::JsRuntime& runtime = const_cast<AbilityRuntime::JsRuntime&>(jsAbility.GetJsRuntime());
195         auto& nativeEngine = runtime.GetNativeEngine();
196         nativeEngine.AllowCrossThreadExecution();
197         AppRecovery::GetInstance().DoSaveAppState(reason, ability);
198         return true;
199     }
200 
201     auto handler = mainHandler_.lock();
202     if (handler == nullptr) {
203         HILOG_ERROR("ScheduleSaveAppState. main handler is not exist");
204         return false;
205     }
206 
207     auto task = [reason, ability]() {
208         AppRecovery::GetInstance().DoSaveAppState(reason, ability);
209     };
210     if (!handler->PostTask(task)) {
211         HILOG_ERROR("Failed to schedule save app state.");
212         return false;
213     }
214 
215     return true;
216 }
217 
SetRestartWant(std::shared_ptr<AAFwk::Want> want)218 void AppRecovery::SetRestartWant(std::shared_ptr<AAFwk::Want> want)
219 {
220     HILOG_DEBUG("AppRecovery SetRestartWant begin");
221     if (!isEnable_) {
222         HILOG_ERROR("AppRecovery SetRestartWant not enabled");
223         return;
224     }
225     want_ = want;
226 }
227 
ScheduleRecoverApp(StateReason reason)228 bool AppRecovery::ScheduleRecoverApp(StateReason reason)
229 {
230     if (!isEnable_) {
231         HILOG_ERROR("AppRecovery ScheduleRecoverApp. is not enabled");
232         return false;
233     }
234 
235     if (!ShouldRecoverApp(reason)) {
236         HILOG_ERROR("AppRecovery ScheduleRecoverApp. is not recover app");
237         return false;
238     }
239 
240     if (abilityRecoverys_.empty()) {
241         HILOG_ERROR("AppRecovery ScheduleRecoverApp ability is nullptr");
242         return false;
243     }
244 
245     if (reason == StateReason::APP_FREEZE) {
246         DoRecoverApp(reason);
247         return true;
248     }
249 
250     auto handler = mainHandler_.lock();
251     if (handler == nullptr) {
252         HILOG_ERROR("AppRecovery ScheduleRecoverApp main handler is not exist");
253         return false;
254     }
255 
256     // may we save state in other thread or just restart.
257     // 1. check whether main handler is still avaliable
258     // 2. do state saving in main thread or just restart app with no state?
259     // 3. create an recovery thread for saving state, just block jsvm mult-thread checking mechaism
260 
261     auto task = [reason]() {
262         AppRecovery::GetInstance().DoRecoverApp(reason);
263     };
264     if (!handler->PostTask(task)) {
265         HILOG_ERROR("Failed to schedule save app state.");
266     }
267 
268     return true;
269 }
270 
TryRecoverApp(StateReason reason)271 bool AppRecovery::TryRecoverApp(StateReason reason)
272 {
273     if (!isEnable_) {
274         return false;
275     }
276 
277     ScheduleSaveAppState(reason);
278     PersistAppState();
279     return ScheduleRecoverApp(reason);
280 }
281 
DoRecoverApp(StateReason reason)282 void AppRecovery::DoRecoverApp(StateReason reason)
283 {
284     HILOG_DEBUG("AppRecovery DoRecoverApp begin");
285     if (abilityRecoverys_.empty()) {
286         HILOG_ERROR("AppRecovery no ability exist! ");
287         return;
288     }
289     AAFwk::Want *want = nullptr;
290     if (want_ != nullptr) {
291         want = want_.get();
292     }
293 
294     if (abilityRecoverys_.size() == 1) {
295         abilityRecoverys_.front()->ScheduleRecoverAbility(reason, want);
296         return;
297     }
298 
299     for (auto itr = abilityRecoverys_.rbegin(); itr != abilityRecoverys_.rend(); itr++) {
300         if ((*itr)->IsOnForeground()) {
301             (*itr)->ScheduleRecoverAbility(reason, want);
302             break;
303         }
304     }
305     HILOG_WARN("AppRecovery no foreground ability, not DoRecoverApp!");
306 }
307 
DoSaveAppState(StateReason reason,uintptr_t ability)308 void AppRecovery::DoSaveAppState(StateReason reason, uintptr_t ability)
309 {
310     HILOG_DEBUG("AppRecovery DoSaveAppState begin");
311     auto appInfo = applicationInfo_.lock();
312     if (appInfo == nullptr || abilityRecoverys_.empty()) {
313         HILOG_ERROR("AppRecovery Application or ability info is not exist.");
314         return;
315     }
316 
317     bool onlySaveTargetAbility = (ability != 0);
318     for (auto& abilityRecoveryRecord : abilityRecoverys_) {
319         if (!onlySaveTargetAbility) {
320             abilityRecoveryRecord->ScheduleSaveAbilityState(reason);
321             HILOG_DEBUG("AppRecovery not onlySaveTargetAbility ScheduleSaveAbilityState");
322             continue;
323         }
324         if (abilityRecoveryRecord->IsSameAbility(ability)) {
325             abilityRecoveryRecord->ScheduleSaveAbilityState(reason);
326             HILOG_DEBUG("AppRecovery IsSameAbility ScheduleSaveAbilityState");
327             break;
328         }
329     }
330 }
331 
EnableAppRecovery(uint16_t restartFlag,uint16_t saveFlag,uint16_t saveMode)332 void AppRecovery::EnableAppRecovery(uint16_t restartFlag, uint16_t saveFlag, uint16_t saveMode)
333 {
334     isEnable_ = true;
335     restartFlag_ = restartFlag;
336     saveOccasion_ = saveFlag;
337     saveMode_ = saveMode;
338 }
339 
ShouldSaveAppState(StateReason reason)340 bool AppRecovery::ShouldSaveAppState(StateReason reason)
341 {
342     bool ret = false;
343     switch (reason) {
344         case StateReason::DEVELOPER_REQUEST:
345             ret = true;
346             break;
347 
348         case StateReason::LIFECYCLE:
349             if ((saveOccasion_ & SaveOccasionFlag::SAVE_WHEN_BACKGROUND) != 0) {
350                 ret = true;
351             }
352             break;
353 
354         case StateReason::CPP_CRASH:
355         case StateReason::JS_ERROR:
356         case StateReason::APP_FREEZE: // appfreeze could not callback to js function safely.
357             if ((saveOccasion_ & SaveOccasionFlag::SAVE_WHEN_ERROR) != 0) {
358                 ret = true;
359             }
360             break;
361     }
362     return ret;
363 }
364 
ShouldRecoverApp(StateReason reason)365 bool AppRecovery::ShouldRecoverApp(StateReason reason)
366 {
367     if (restartFlag_ == RestartFlag::NO_RESTART) {
368         return false;
369     }
370 
371     bool ret = false;
372     bool isAlwaysStart = false;
373     if (restartFlag_ == RestartFlag::ALWAYS_RESTART) {
374         isAlwaysStart = true;
375     }
376     switch (reason) {
377         case StateReason::DEVELOPER_REQUEST:
378             ret = true;
379             break;
380 
381         case StateReason::LIFECYCLE:
382             ret = false;
383             break;
384 
385         case StateReason::CPP_CRASH:
386             ret = false;
387             break;
388 
389         case StateReason::JS_ERROR:
390             if (isAlwaysStart || (restartFlag_ & RestartFlag::RESTART_WHEN_JS_CRASH) != 0) {
391                 ret = true;
392             }
393             break;
394 
395         case StateReason::APP_FREEZE:
396             if (isAlwaysStart || (restartFlag_ & RestartFlag::RESTART_WHEN_APP_FREEZE) != 0) {
397                 ret = true;
398             }
399             break;
400     }
401     return ret;
402 }
403 
DeleteInValidMissionFiles()404 void AppRecovery::DeleteInValidMissionFiles()
405 {
406     auto context = AbilityRuntime::Context::GetApplicationContext();
407     if (context == nullptr) {
408         return;
409     }
410 
411     std::string fileDir = context->GetFilesDir();
412     HILOG_DEBUG("AppRecovery DeleteInValidMissionFiles fileDir: %{public}s", fileDir.c_str());
413     if (fileDir.empty() || !OHOS::FileExists(fileDir)) {
414         HILOG_DEBUG("AppRecovery DeleteInValidMissionFiles fileDir is empty or fileDir is not exists.");
415         return;
416     }
417     std::vector<int32_t> missionIds;
418     std::vector<MissionVaildResult> results;
419 
420     if (!GetMissionIds(fileDir, missionIds)) {
421         HILOG_ERROR("AppRecovery get mssion file id error.");
422         return;
423     }
424     if (missionIds.empty()) {
425         HILOG_DEBUG("AppRecovery no mission file, no need delete it.");
426         return;
427     }
428     std::shared_ptr<AAFwk::AbilityManagerClient> abilityMgr = AAFwk::AbilityManagerClient::GetInstance();
429     if (abilityMgr == nullptr) {
430         HILOG_ERROR("AppRecovery DeleteInValidMissionFiles. abilityMgr client is not exist.");
431         return;
432     }
433     abilityMgr->IsValidMissionIds(missionIds, results);
434     if (results.empty()) {
435         HILOG_ERROR("AppRecovery DeleteInValidMissionFiles. results is empty.");
436         return;
437     }
438     for (auto& item : results) {
439         HILOG_INFO("AppRecovery missionResult: missionId: %{public}d, isValid: %{public}d", item.missionId,
440             item.isVaild);
441         if (!item.isVaild) {
442             DeleteInValidMissionFileById(fileDir, item.missionId);
443         }
444     }
445 }
446 
DeleteInValidMissionFileById(std::string fileDir,int32_t missionId)447 void AppRecovery::DeleteInValidMissionFileById(std::string fileDir, int32_t missionId)
448 {
449     std::string fileName = std::to_string(missionId) + ".state";
450     std::string file = fileDir + "/" + fileName;
451     bool ret = OHOS::RemoveFile(file);
452     if (!ret) {
453         HILOG_ERROR("AppRecovery delete the file: %{public}s failed", file.c_str());
454     }
455     HILOG_DEBUG("AppRecovery delete the file: %{public}s done", file.c_str());
456 }
457 
GetMissionIds(std::string path,std::vector<int32_t> & missionIds)458 bool AppRecovery::GetMissionIds(std::string path, std::vector<int32_t> &missionIds)
459 {
460     DIR *dir = opendir(path.c_str());
461     if (dir == nullptr) {
462         HILOG_ERROR("AppRecovery GetMissionIds open dir error.");
463         return false;
464     }
465     struct dirent *ptr;
466     while ((ptr = readdir(dir)) != nullptr) {
467         if (ptr == nullptr) {
468             HILOG_ERROR("AppRecovery GetMissionIds read dir error.");
469             return false;
470         }
471         if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
472             continue;
473         } else if (ptr->d_type == DT_REG) {
474             std::string fileName = ptr->d_name;
475             auto pos = fileName.find_first_of(".");
476             if (pos != std::string::npos) {
477                 std::string missionIdStr = fileName.substr(0, pos);
478                 missionIds.push_back(atoi(missionIdStr.c_str()));
479             }
480         } else {
481             continue;
482         }
483     }
484     closedir(dir);
485     return true;
486 }
487 
PersistAppState()488 bool AppRecovery::PersistAppState()
489 {
490     if (saveMode_ == SaveModeFlag::SAVE_WITH_FILE) {
491         return true;
492     }
493 
494     bool ret = true;
495     for (auto& abilityRecovery : abilityRecoverys_) {
496         ret = ret && abilityRecovery->PersistState();
497     }
498     return ret;
499 }
500 
IsEnabled() const501 bool AppRecovery::IsEnabled() const
502 {
503     return isEnable_;
504 }
505 
GetRestartFlag() const506 uint16_t AppRecovery::GetRestartFlag() const
507 {
508     return restartFlag_;
509 }
510 
GetSaveOccasionFlag() const511 uint16_t AppRecovery::GetSaveOccasionFlag() const
512 {
513     return saveOccasion_;
514 }
515 
GetSaveModeFlag() const516 uint16_t AppRecovery::GetSaveModeFlag() const
517 {
518     return saveMode_;
519 }
520 }  // namespace AbilityRuntime
521 }  // namespace OHOS
522