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,IServiceReverseType::Scenario scenario,ErrCode res)43 void ExtDiedClearFailRadarReport(const string& bundleName, IServiceReverseType::Scenario scenario, ErrCode res)
44 {
45 if (res == ERR_OK) {
46 return;
47 }
48 AppRadar::Info info(bundleName, "", "");
49 if (scenario == IServiceReverseType::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 == IServiceReverseType::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("Unexpected exception");
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::UNKNOWN) {
97 HILOGE("Current action is unknown, bundleName:%{public}s", bundleName.c_str());
98 return;
99 }
100 try {
101 HILOGI("Start current bundle task, bundleName:%{public}s, action:%{public}d", bundleName.c_str(), action);
102 StartExecuteBundleTask(bundleName, action);
103 } catch(...) {
104 HILOGE("Unexpected exception");
105 return;
106 }
107 }
108
RemoveExtConn(const string & bundleName)109 void SchedScheduler::RemoveExtConn(const string &bundleName)
110 {
111 unique_lock<shared_mutex> lock(lock_);
112 auto iter = find_if(bundleTimeVec_.begin(), bundleTimeVec_.end(), [&bundleName](auto &obj) {
113 auto &[bName, iTime] = obj;
114 return bName == bundleName;
115 });
116 if (iter != bundleTimeVec_.end()) {
117 auto &[bName, iTime] = *iter;
118 HILOGE("bundleName = %{public}s , iTime = %{public}d", bName.data(), iTime);
119 extTime_.Unregister(iTime);
120 bundleTimeVec_.erase(iter);
121 }
122 }
123
StartTimer()124 void SchedScheduler::StartTimer()
125 {
126 extTime_.Setup();
127 TryUnloadServiceTimer();
128 }
129
TryUnloadServiceTimer(bool force)130 void SchedScheduler::TryUnloadServiceTimer(bool force)
131 {
132 auto tryUnload = [sessionPtr {sessionPtr_}]() {
133 auto ptr = sessionPtr.promote();
134 if (ptr && ptr->GetSessionCnt() > 0) {
135 return;
136 }
137 HILOGI("Unload system ability");
138 sptr<ISystemAbilityManager> saManager =
139 OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
140 if (saManager == nullptr) {
141 HILOGE("UnloadSA, GetSystemAbilityManager is null.");
142 return;
143 }
144 int32_t result = saManager->UnloadSystemAbility(FILEMANAGEMENT_BACKUP_SERVICE_SA_ID);
145 if (result != ERR_OK) {
146 HILOGE("UnloadSA, UnloadSystemAbility result: %{public}d", result);
147 return;
148 }
149 };
150
151 static atomic<uint32_t> timerEventId;
152 // When force is false, only one timer is allowed to be registered.
153 if (!force) {
154 if (timerEventId != 0) {
155 return;
156 }
157 constexpr int checkingIntervalInMs = 30000;
158 auto tmpTimerEventId = extTime_.Register(tryUnload, checkingIntervalInMs);
159 uint32_t tmp = 0;
160 if (timerEventId.compare_exchange_strong(tmp, tmpTimerEventId)) {
161 return;
162 }
163 extTime_.Unregister(tmpTimerEventId);
164 }
165
166 tryUnload();
167 }
168
TryUnloadService()169 void SchedScheduler::TryUnloadService()
170 {
171 auto tryUnload = []() {
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 threadPool_.AddTask(tryUnload);
186 }
187
ClearSchedulerData()188 void SchedScheduler::ClearSchedulerData()
189 {
190 unique_lock<shared_mutex> lock(lock_);
191 for (const auto &bundleTime : bundleTimeVec_) {
192 auto &[bName, iTime] = bundleTime;
193 extTime_.Unregister(iTime);
194 }
195 bundleTimeVec_.clear();
196 }
197
StartExecuteBundleTask(const std::string & bundleName,BConstants::ServiceSchedAction action)198 void SchedScheduler::StartExecuteBundleTask(const std::string &bundleName, BConstants::ServiceSchedAction action)
199 {
200 if (action == BConstants::ServiceSchedAction::START) {
201 // register timer for connect extension
202 auto callStart = [reversePtr {reversePtr_}, bundleName]() {
203 HILOGE("Extension connect failed = %{public}s", bundleName.data());
204 auto ptr = reversePtr.promote();
205 if (ptr) {
206 ptr->ExtConnectFailed(bundleName, BError(BError::Codes::SA_BOOT_EXT_TIMEOUT));
207 }
208 };
209 auto iTime = extTime_.Register(callStart, BConstants::EXT_CONNECT_MAX_TIME, true);
210 unique_lock<shared_mutex> lock(lock_);
211 bundleTimeVec_.emplace_back(make_tuple(bundleName, iTime));
212 lock.unlock();
213 // launch extension
214 if (reversePtr_ != nullptr) {
215 ErrCode errCode = reversePtr_->LaunchBackupExtension(bundleName);
216 if (errCode) {
217 reversePtr_->ExtConnectFailed(bundleName, errCode);
218 }
219 }
220 } else if (action == BConstants::ServiceSchedAction::RUNNING) {
221 HILOGI("Current bundle %{public}s process is running", bundleName.data());
222 //notify AppGallery to start restore
223 if (reversePtr_ != nullptr) {
224 reversePtr_->StartRunningTimer(bundleName);
225 reversePtr_->SendStartAppGalleryNotify(bundleName);
226 reversePtr_->ExtStart(bundleName);
227 }
228 } else if (action == BConstants::ServiceSchedAction::CLEAN) {
229 HILOGI("Current bundle %{public}s process is cleaning", bundleName.data());
230 bool isRestoreEnd = sessionPtr_->GetIsRestoreEnd(bundleName);
231 ErrCode res = reversePtr_->ClearResidualBundleData(bundleName);
232 reversePtr_->DoNoticeClientFinish(bundleName, BError(BError::Codes::EXT_ABILITY_DIED), isRestoreEnd);
233 IServiceReverseType::Scenario scenario = sessionPtr_->GetScenario();
234 ExtDiedClearFailRadarReport(bundleName, scenario, res);
235 }
236 }
237 }; // namespace OHOS::FileManagement::Backup