• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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