1 /*
2 * Copyright (c) 2022-2023 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 "filemgmt_libhilog.h"
32 #include "iservice_registry.h"
33 #include "module_external/bms_adapter.h"
34 #include "module_external/inner_receiver_impl.h"
35 #include "module_ipc/service.h"
36 #include "module_ipc/svc_session_manager.h"
37 #include "system_ability_definition.h"
38
39 namespace OHOS::FileManagement::Backup {
40 using namespace std;
41
Sched(string bundleName)42 void SchedScheduler::Sched(string bundleName)
43 {
44 if (bundleName == "") {
45 if (!sessionPtr_->GetSchedBundleName(bundleName)) {
46 return;
47 }
48 BConstants::ServiceSchedAction action = sessionPtr_->GetServiceSchedAction(bundleName);
49 if (action == BConstants::ServiceSchedAction::WAIT) {
50 sessionPtr_->SetServiceSchedAction(bundleName, BConstants::ServiceSchedAction::INSTALLING);
51 }
52 }
53 HILOGE("Sched bundleName %{public}s", bundleName.data());
54 auto callStart = [schedPtr {wptr(this)}, bundleName]() {
55 try {
56 auto ptr = schedPtr.promote();
57 ptr->ExecutingQueueTasks(bundleName);
58 } catch (const BError &e) {
59 HILOGE("%{public}s", e.what());
60 } catch (const exception &e) {
61 HILOGE("%{public}s", e.what());
62 } catch (...) {
63 HILOGE("");
64 }
65 };
66 threadPool_.AddTask(callStart);
67 }
68
ExecutingQueueTasks(const string & bundleName)69 void SchedScheduler::ExecutingQueueTasks(const string &bundleName)
70 {
71 HILOGE("start");
72 InstallingState(bundleName);
73 BConstants::ServiceSchedAction action = sessionPtr_->GetServiceSchedAction(bundleName);
74 if (action == BConstants::ServiceSchedAction::START) {
75 // 注册启动定时器
76 auto callStart = [reversePtr {reversePtr_}, bundleName]() {
77 HILOGE("Extension connect failed = %{public}s", bundleName.data());
78 auto ptr = reversePtr.promote();
79 if (ptr) {
80 ptr->ExtConnectFailed(bundleName, EPERM);
81 }
82 };
83 auto iTime = extTime_.Register(callStart, BConstants::EXT_CONNECT_MAX_TIME);
84 unique_lock<shared_mutex> lock(lock_);
85 bundleTimeVec_.emplace_back(make_tuple(bundleName, iTime));
86 lock.unlock();
87 // 启动extension
88 reversePtr_->LaunchBackupExtension(bundleName);
89 } else if (action == BConstants::ServiceSchedAction::RUNNING) {
90 unique_lock<shared_mutex> lock(lock_);
91 auto iter = find_if(bundleTimeVec_.begin(), bundleTimeVec_.end(), [&bundleName](auto &obj) {
92 auto &[bName, iTime] = obj;
93 return bName == bundleName;
94 });
95 if (iter == bundleTimeVec_.end()) {
96 throw BError(BError::Codes::SA_INVAL_ARG, "Failed to find timer");
97 }
98 auto &[bName, iTime] = *iter;
99 // 移除启动定时器 当前逻辑无启动成功后的ext心跳检测
100 extTime_.Unregister(iTime);
101 lock.unlock();
102 // 开始执行备份恢复流程
103 reversePtr_->ExtStart(bundleName);
104 }
105 }
106
RemoveExtConn(const string & bundleName)107 void SchedScheduler::RemoveExtConn(const string &bundleName)
108 {
109 unique_lock<shared_mutex> lock(lock_);
110 auto iter = find_if(bundleTimeVec_.begin(), bundleTimeVec_.end(), [&bundleName](auto &obj) {
111 auto &[bName, iTime] = obj;
112 return bName == bundleName;
113 });
114 if (iter != bundleTimeVec_.end()) {
115 auto &[bName, iTime] = *iter;
116 HILOGE("bundleName = %{public}s , iTime = %{public}d", bName.data(), iTime);
117 extTime_.Unregister(iTime);
118 bundleTimeVec_.erase(iter);
119 }
120 }
121
GetRealPath(string & path)122 static bool GetRealPath(string &path)
123 {
124 unique_ptr<char[]> absPath = make_unique<char[]>(PATH_MAX + 1);
125 if (realpath(path.c_str(), absPath.get()) == nullptr) {
126 return false;
127 }
128 path = absPath.get();
129 return true;
130 }
131
InstallingState(const string & bundleName)132 void SchedScheduler::InstallingState(const string &bundleName)
133 {
134 BConstants::ServiceSchedAction action = sessionPtr_->GetServiceSchedAction(bundleName);
135 if (action == BConstants::ServiceSchedAction::INSTALLING) {
136 IServiceReverse::Scenario scenario = sessionPtr_->GetScenario();
137 if (scenario == IServiceReverse::Scenario::BACKUP || !sessionPtr_->GetNeedToInstall(bundleName)) {
138 sessionPtr_->SetServiceSchedAction(bundleName, BConstants::ServiceSchedAction::START);
139 return;
140 }
141 string state = sessionPtr_->GetInstallState(bundleName);
142 string path = BConstants::GetSaBundleBackupRootDir(sessionPtr_->GetSessionUserId()).append(bundleName);
143 string filePath = path + "/bundle.hap";
144
145 if (state == BConstants::RESTORE_INSTALL_PATH) {
146 if (!ForceCreateDirectory(path)) {
147 throw BError(BError::Codes::SA_INVAL_ARG, string("Failed to create directory"));
148 }
149 auto ret = GetRealPath(filePath);
150 HILOGE("ret = %{public}d", ret);
151 sessionPtr_->GetServiceReverseProxy()->RestoreOnFileReady(
152 bundleName, state,
153 UniqueFd(open(filePath.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IROTH)));
154 } else if (state == "OK") {
155 if (!GetRealPath(filePath)) {
156 throw BError(BError::Codes::SA_INVAL_ARG, string("File path is invalid"));
157 }
158 if (access(filePath.data(), F_OK) != 0) {
159 throw BError(BError::Codes::SA_INVAL_ARG, string("File already exists"));
160 }
161 sptr<InnerReceiverImpl> statusReceiver = sptr(new InnerReceiverImpl(bundleName, wptr(this)));
162 ErrCode err = BundleMgrAdapter::Install(statusReceiver, filePath, sessionPtr_->GetSessionUserId());
163 if (err != ERR_OK) {
164 InstallSuccess(bundleName, err);
165 }
166 }
167 }
168 }
169
TryUnloadServiceTimer(bool force)170 void SchedScheduler::TryUnloadServiceTimer(bool force)
171 {
172 auto tryUnload = [sessionPtr {sessionPtr_}]() {
173 auto ptr = sessionPtr.promote();
174 if (ptr && !ptr->NeedToUnloadService()) {
175 return;
176 }
177 HILOGI("Unload system ability");
178 sptr<ISystemAbilityManager> saManager =
179 OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
180 if (saManager == nullptr) {
181 HILOGE("UnloadSA, GetSystemAbilityManager is null.");
182 return;
183 }
184 int32_t result = saManager->UnloadSystemAbility(FILEMANAGEMENT_BACKUP_SERVICE_SA_ID);
185 if (result != ERR_OK) {
186 HILOGE("UnloadSA, UnloadSystemAbility result: %{public}d", result);
187 return;
188 }
189 };
190
191 static atomic<uint32_t> timerEventId;
192 // When force is false, only one timer is allowed to be registered.
193 if (!force) {
194 if (timerEventId != 0) {
195 return;
196 }
197 constexpr int checkingIntervalInMs = 30000;
198 auto tmpTimerEventId = extTime_.Register(tryUnload, checkingIntervalInMs);
199 uint32_t tmp = 0;
200 if (timerEventId.compare_exchange_strong(tmp, tmpTimerEventId)) {
201 return;
202 }
203 extTime_.Unregister(tmpTimerEventId);
204 }
205
206 // When force is true, the timer is unregistered immediately and then try to unload the service.
207 if (auto tmp = timerEventId.exchange(0); tmp != 0) {
208 extTime_.Unregister(tmp);
209 }
210 tryUnload();
211 }
212
InstallSuccess(const std::string & bundleName,const int32_t resultCode)213 void SchedScheduler::InstallSuccess(const std::string &bundleName, const int32_t resultCode)
214 {
215 if (!resultCode) {
216 sessionPtr_->SetServiceSchedAction(bundleName, BConstants::ServiceSchedAction::START);
217 Sched(bundleName);
218 } else {
219 sessionPtr_->GetServiceReverseProxy()->RestoreOnBundleStarted(resultCode, bundleName);
220 sessionPtr_->RemoveExtInfo(bundleName);
221 }
222 string path = BConstants::GetSaBundleBackupRootDir(sessionPtr_->GetSessionUserId()).append(bundleName);
223 if (!ForceRemoveDirectory(path)) {
224 HILOGE("RemoveDirectory failed");
225 }
226 }
227 }; // namespace OHOS::FileManagement::Backup
228