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 "module_sched/sched_scheduler.h"
17 
18 #include <atomic>
19 #include <cstdint>
20 #include <cstdio>
21 #include <fcntl.h>
22 #include <tuple>
23 #include <utility>
24 
25 #include <sys/stat.h>
26 
27 #include <directory_ex.h>
28 #include <unique_fd.h>
29 
30 #include "b_error/b_error.h"
31 #include "b_ohos/startup/backup_para.h"
32 #include "b_radar/b_radar.h"
33 #include "filemgmt_libhilog.h"
34 #include "iservice_registry.h"
35 #include "module_external/bms_adapter.h"
36 #include "module_ipc/service.h"
37 #include "module_ipc/svc_session_manager.h"
38 #include "system_ability_definition.h"
39 
40 namespace OHOS::FileManagement::Backup {
41 using namespace std;
42 
ExtDiedClearFailRadarReport(const string & bundleName,IServiceReverse::Scenario scenario,ErrCode res)43 void ExtDiedClearFailRadarReport(const string& bundleName, IServiceReverse::Scenario scenario, ErrCode res)
44 {
45     if (res == ERR_OK) {
46         return;
47     }
48     AppRadar::Info info(bundleName, "", "");
49     if (scenario == IServiceReverse::Scenario::RESTORE) {
50         AppRadar::GetInstance().RecordRestoreFuncRes(info, "SchedScheduler::ExecutingQueueTasks",
51             AppRadar::GetInstance().GetUserId(), BizStageRestore::BIZ_STAGE_EXTENSION_ABNORMAL_EXIT_CLEAR_FAIL, res);
52     } else if (scenario == IServiceReverse::Scenario::BACKUP) {
53         AppRadar::GetInstance().RecordBackupFuncRes(info, "SchedScheduler::ExecutingQueueTasks",
54             AppRadar::GetInstance().GetUserId(), BizStageBackup::BIZ_STAGE_EXTENSION_ABNORMAL_EXIT_CLEAR_FAIL, res);
55     }
56 }
57 
Sched(string bundleName)58 void SchedScheduler::Sched(string bundleName)
59 {
60     if (bundleName == "") {
61         if (sessionPtr_ == nullptr) {
62             HILOGE("Sched bundle %{public}s error, sessionPtr is empty", bundleName.c_str());
63             return;
64         }
65         if (!sessionPtr_->GetSchedBundleName(bundleName)) {
66             return;
67         }
68     }
69     HILOGE("Sched bundleName %{public}s", bundleName.data());
70     auto callStart = [schedPtr {wptr(this)}, bundleName]() {
71         try {
72             auto ptr = schedPtr.promote();
73             if (ptr == nullptr) {
74                 HILOGE("Sched bundle %{public}s error, ptr is empty", bundleName.c_str());
75                 return;
76             }
77             ptr->ExecutingQueueTasks(bundleName);
78         } catch (const BError &e) {
79             HILOGE("%{public}s", e.what());
80         } catch (const exception &e) {
81             HILOGE("%{public}s", e.what());
82         } catch (...) {
83             HILOGE("");
84         }
85     };
86     threadPool_.AddTask(callStart);
87 }
88 
ExecutingQueueTasks(const string & bundleName)89 void SchedScheduler::ExecutingQueueTasks(const string &bundleName)
90 {
91     if (sessionPtr_ == nullptr) {
92         HILOGE("ExecutingQueueTasks bundle %{public}s error, sessionPtr is empty", bundleName.c_str());
93         return;
94     }
95     BConstants::ServiceSchedAction action = sessionPtr_->GetServiceSchedAction(bundleName);
96     if (action == BConstants::ServiceSchedAction::START) {
97         // register timer for connect extension
98         auto callStart = [reversePtr {reversePtr_}, bundleName]() {
99             HILOGE("Extension connect failed = %{public}s", bundleName.data());
100             auto ptr = reversePtr.promote();
101             if (ptr) {
102                 ptr->ExtConnectFailed(bundleName, BError(BError::Codes::SA_BOOT_EXT_TIMEOUT));
103             }
104         };
105         auto iTime = extTime_.Register(callStart, BConstants::EXT_CONNECT_MAX_TIME, true);
106         unique_lock<shared_mutex> lock(lock_);
107         bundleTimeVec_.emplace_back(make_tuple(bundleName, iTime));
108         lock.unlock();
109         // launch extension
110         if (reversePtr_ != nullptr) {
111             ErrCode errCode = reversePtr_->LaunchBackupExtension(bundleName);
112             if (errCode) {
113                 reversePtr_->ExtConnectFailed(bundleName, errCode);
114             }
115         }
116     } else if (action == BConstants::ServiceSchedAction::RUNNING) {
117         HILOGI("Current bundle %{public}s process is running", bundleName.data());
118         unique_lock<shared_mutex> lock(lock_);
119         auto iter = find_if(bundleTimeVec_.begin(), bundleTimeVec_.end(), [&bundleName](auto &obj) {
120             auto &[bName, iTime] = obj;
121             return bName == bundleName;
122         });
123         if (iter == bundleTimeVec_.end()) {
124             throw BError(BError::Codes::SA_INVAL_ARG, "Failed to find timer");
125         }
126         auto &[bName, iTime] = *iter;
127         // unregister timer
128         extTime_.Unregister(iTime);
129         lock.unlock();
130         //notify AppGallery to start restore
131         if (reversePtr_ != nullptr) {
132             reversePtr_->StartRunningTimer(bundleName);
133             reversePtr_->SendStartAppGalleryNotify(bundleName);
134             reversePtr_->ExtStart(bundleName);
135         }
136     } else if (action == BConstants::ServiceSchedAction::CLEAN) {
137         HILOGI("Current bundle %{public}s process is cleaning", bundleName.data());
138         ErrCode res = reversePtr_->ClearResidualBundleData(bundleName);
139         IServiceReverse::Scenario scenario = sessionPtr_->GetScenario();
140         ExtDiedClearFailRadarReport(bundleName, scenario, res);
141     }
142 }
143 
RemoveExtConn(const string & bundleName)144 void SchedScheduler::RemoveExtConn(const string &bundleName)
145 {
146     unique_lock<shared_mutex> lock(lock_);
147     auto iter = find_if(bundleTimeVec_.begin(), bundleTimeVec_.end(), [&bundleName](auto &obj) {
148         auto &[bName, iTime] = obj;
149         return bName == bundleName;
150     });
151     if (iter != bundleTimeVec_.end()) {
152         auto &[bName, iTime] = *iter;
153         HILOGE("bundleName = %{public}s , iTime = %{public}d", bName.data(), iTime);
154         extTime_.Unregister(iTime);
155         bundleTimeVec_.erase(iter);
156     }
157 }
158 
StartTimer()159 void SchedScheduler::StartTimer()
160 {
161     extTime_.Setup();
162     TryUnloadServiceTimer();
163 }
164 
TryUnloadServiceTimer(bool force)165 void SchedScheduler::TryUnloadServiceTimer(bool force)
166 {
167     auto tryUnload = [sessionPtr {sessionPtr_}]() {
168         auto ptr = sessionPtr.promote();
169         if (ptr && ptr->GetSessionCnt() > 0) {
170             return;
171         }
172         HILOGI("Unload system ability");
173         sptr<ISystemAbilityManager> saManager =
174             OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
175         if (saManager == nullptr) {
176             HILOGE("UnloadSA, GetSystemAbilityManager is null.");
177             return;
178         }
179         int32_t result = saManager->UnloadSystemAbility(FILEMANAGEMENT_BACKUP_SERVICE_SA_ID);
180         if (result != ERR_OK) {
181             HILOGE("UnloadSA, UnloadSystemAbility result: %{public}d", result);
182             return;
183         }
184     };
185 
186     static atomic<uint32_t> timerEventId;
187     // When force is false, only one timer is allowed to be registered.
188     if (!force) {
189         if (timerEventId != 0) {
190             return;
191         }
192         constexpr int checkingIntervalInMs = 30000;
193         auto tmpTimerEventId = extTime_.Register(tryUnload, checkingIntervalInMs);
194         uint32_t tmp = 0;
195         if (timerEventId.compare_exchange_strong(tmp, tmpTimerEventId)) {
196             return;
197         }
198         extTime_.Unregister(tmpTimerEventId);
199     }
200 
201     tryUnload();
202 }
203 
TryUnloadService()204 void SchedScheduler::TryUnloadService()
205 {
206     auto tryUnload = []() {
207         HILOGI("Unload system ability");
208         sptr<ISystemAbilityManager> saManager =
209             OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
210         if (saManager == nullptr) {
211             HILOGE("UnloadSA, GetSystemAbilityManager is null.");
212             return;
213         }
214         int32_t result = saManager->UnloadSystemAbility(FILEMANAGEMENT_BACKUP_SERVICE_SA_ID);
215         if (result != ERR_OK) {
216             HILOGE("UnloadSA, UnloadSystemAbility result: %{public}d", result);
217             return;
218         }
219     };
220     threadPool_.AddTask(tryUnload);
221 }
222 
ClearSchedulerData()223 void SchedScheduler::ClearSchedulerData()
224 {
225     unique_lock<shared_mutex> lock(lock_);
226     for (auto &bundleTime : bundleTimeVec_) {
227         auto &[bName, iTime] = bundleTime;
228         extTime_.Unregister(iTime);
229     }
230     bundleTimeVec_.clear();
231 }
232 }; // namespace OHOS::FileManagement::Backup
233