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_->SendStartAppGalleryNotify(bundleName);
133 reversePtr_->ExtStart(bundleName);
134 }
135 } else if (action == BConstants::ServiceSchedAction::CLEAN) {
136 HILOGI("Current bundle %{public}s process is cleaning", bundleName.data());
137 ErrCode res = reversePtr_->ClearResidualBundleData(bundleName);
138 IServiceReverse::Scenario scenario = sessionPtr_->GetScenario();
139 ExtDiedClearFailRadarReport(bundleName, scenario, res);
140 }
141 }
142
RemoveExtConn(const string & bundleName)143 void SchedScheduler::RemoveExtConn(const string &bundleName)
144 {
145 unique_lock<shared_mutex> lock(lock_);
146 auto iter = find_if(bundleTimeVec_.begin(), bundleTimeVec_.end(), [&bundleName](auto &obj) {
147 auto &[bName, iTime] = obj;
148 return bName == bundleName;
149 });
150 if (iter != bundleTimeVec_.end()) {
151 auto &[bName, iTime] = *iter;
152 HILOGE("bundleName = %{public}s , iTime = %{public}d", bName.data(), iTime);
153 extTime_.Unregister(iTime);
154 bundleTimeVec_.erase(iter);
155 }
156 }
157
StartTimer()158 void SchedScheduler::StartTimer()
159 {
160 extTime_.Setup();
161 TryUnloadServiceTimer();
162 }
163
TryUnloadServiceTimer(bool force)164 void SchedScheduler::TryUnloadServiceTimer(bool force)
165 {
166 auto tryUnload = [sessionPtr {sessionPtr_}]() {
167 auto ptr = sessionPtr.promote();
168 if (ptr && ptr->GetSessionCnt() > 0) {
169 return;
170 }
171 HILOGI("Unload system ability");
172 sptr<ISystemAbilityManager> saManager =
173 OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
174 if (saManager == nullptr) {
175 HILOGE("UnloadSA, GetSystemAbilityManager is null.");
176 return;
177 }
178 int32_t result = saManager->UnloadSystemAbility(FILEMANAGEMENT_BACKUP_SERVICE_SA_ID);
179 if (result != ERR_OK) {
180 HILOGE("UnloadSA, UnloadSystemAbility result: %{public}d", result);
181 return;
182 }
183 };
184
185 static atomic<uint32_t> timerEventId;
186 // When force is false, only one timer is allowed to be registered.
187 if (!force) {
188 if (timerEventId != 0) {
189 return;
190 }
191 constexpr int checkingIntervalInMs = 30000;
192 auto tmpTimerEventId = extTime_.Register(tryUnload, checkingIntervalInMs);
193 uint32_t tmp = 0;
194 if (timerEventId.compare_exchange_strong(tmp, tmpTimerEventId)) {
195 return;
196 }
197 extTime_.Unregister(tmpTimerEventId);
198 }
199
200 tryUnload();
201 }
202
TryUnloadService()203 void SchedScheduler::TryUnloadService()
204 {
205 auto tryUnload = []() {
206 HILOGI("Unload system ability");
207 sptr<ISystemAbilityManager> saManager =
208 OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
209 if (saManager == nullptr) {
210 HILOGE("UnloadSA, GetSystemAbilityManager is null.");
211 return;
212 }
213 int32_t result = saManager->UnloadSystemAbility(FILEMANAGEMENT_BACKUP_SERVICE_SA_ID);
214 if (result != ERR_OK) {
215 HILOGE("UnloadSA, UnloadSystemAbility result: %{public}d", result);
216 return;
217 }
218 };
219 threadPool_.AddTask(tryUnload);
220 }
221
ClearSchedulerData()222 void SchedScheduler::ClearSchedulerData()
223 {
224 unique_lock<shared_mutex> lock(lock_);
225 for (auto &bundleTime : bundleTimeVec_) {
226 auto &[bName, iTime] = bundleTime;
227 extTime_.Unregister(iTime);
228 }
229 bundleTimeVec_.clear();
230 }
231 }; // namespace OHOS::FileManagement::Backup
232