1 /*
2 * Copyright (c) 2022 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 "quick_fix_boot_scanner.h"
17
18 #include "app_log_tag_wrapper.h"
19 #include "bundle_mgr_service.h"
20 #include "installd_client.h"
21 #include "quick_fix_deleter.h"
22 #include "quick_fix_delete_state.h"
23 #include "quick_fix_deployer.h"
24 #include "quick_fix_deploy_state.h"
25 #include "quick_fix_switcher.h"
26 #include "quick_fix_switch_state.h"
27
28 namespace OHOS {
29 namespace AppExecFwk {
ProcessQuickFixBootUp()30 void QuickFixBootScanner::ProcessQuickFixBootUp()
31 {
32 LOG_I(BMS_TAG_DEFAULT, "start to process quick fix boot up");
33 quickFixDataMgr_ = DelayedSingleton<QuickFixDataMgr>::GetInstance();
34 if (quickFixDataMgr_ == nullptr) {
35 LOG_E(BMS_TAG_DEFAULT, "quickFixDataMgr_ is nullptr");
36 return;
37 }
38
39 std::map<std::string, InnerAppQuickFix> quickFixInfoMap;
40 auto ret = quickFixDataMgr_->QueryAllInnerAppQuickFix(quickFixInfoMap);
41 if (!ret || quickFixInfoMap.empty()) {
42 LOG_W(BMS_TAG_DEFAULT, "no quick fix info in db");
43 RestoreQuickFix();
44 return;
45 }
46
47 for (const auto &quickFixInfo : quickFixInfoMap) {
48 auto quickFixStatus = quickFixInfo.second.GetQuickFixMark().status;
49 LOG_D(BMS_TAG_DEFAULT, "quick fix scan bundle %{public}s, status is %{public}d",
50 quickFixInfo.first.c_str(), quickFixStatus);
51 if ((quickFixStatus == QuickFixStatus::DEFAULT_STATUS) || (quickFixStatus == QuickFixStatus::DELETE_END) ||
52 (quickFixStatus == QuickFixStatus::SWITCH_END) || (quickFixStatus== QuickFixStatus::DELETE_START)) {
53 state_ = std::make_shared<QuickFixDeleteState>(quickFixInfo.first);
54 }
55 if (quickFixStatus == QuickFixStatus::DEPLOY_START) {
56 state_ = std::make_shared<QuickFixDeployState>(quickFixInfo.second);
57 }
58 if ((quickFixStatus == QuickFixStatus::DEPLOY_END) || (quickFixStatus == QuickFixStatus::SWITCH_ENABLE_START)) {
59 state_ = std::make_shared<QuickFixSwitchState>(quickFixInfo.first, true);
60 }
61 if (quickFixStatus == QuickFixStatus::SWITCH_DISABLE_START) {
62 state_ = std::make_shared<QuickFixSwitchState>(quickFixInfo.first, false);
63 }
64 auto res = ProcessState();
65 if (res != ERR_OK) {
66 LOG_E(BMS_TAG_DEFAULT, "quick fix info %{public}s is processed failed with error %{public}d",
67 quickFixInfo.first.c_str(), res);
68 quickFixDataMgr_->DeleteInnerAppQuickFix(quickFixInfo.first);
69 }
70 state_.reset();
71 }
72 RemoveInvalidDir();
73 LOG_I(BMS_TAG_DEFAULT, "process quick fix boot up completely");
74 }
75
SetQuickFixState(const std::shared_ptr<QuickFixState> & state)76 void QuickFixBootScanner::SetQuickFixState(const std::shared_ptr<QuickFixState> &state)
77 {
78 state_.reset();
79 state_ = state;
80 }
81
ProcessState() const82 ErrCode QuickFixBootScanner::ProcessState() const
83 {
84 if (state_ == nullptr) {
85 LOG_E(BMS_TAG_DEFAULT, "state_ is nullptr");
86 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
87 }
88 return state_->Process();
89 }
90
RestoreQuickFix()91 void QuickFixBootScanner::RestoreQuickFix()
92 {
93 LOG_I(BMS_TAG_DEFAULT, "start to RestoreQuickFix");
94 std::vector<std::string> dirVec;
95 if (InstalldClient::GetInstance()->ObtainQuickFixFileDir(Constants::BUNDLE_CODE_DIR, dirVec) != ERR_OK) {
96 LOG_E(BMS_TAG_DEFAULT, "RestoreQuickFix failed due to obtained quick fix file dir failed");
97 return;
98 }
99 ProcessQuickFixDir(dirVec);
100
101 if (quickFixInfoMap_.empty()) {
102 LOG_W(BMS_TAG_DEFAULT, "no quick fix info in quickFixInfoMap_");
103 return;
104 }
105 for (const auto &quickFix : quickFixInfoMap_) {
106 ApplicationInfo appInfo;
107 // 1. no bundleInfo, then to remove the quick fix file
108 if (!GetApplicationInfo(quickFix.first, quickFix.second.second, appInfo)) {
109 LOG_W(BMS_TAG_DEFAULT, "appInfo is no existed, the quick info file need to be deleted");
110 continue;
111 }
112 // 2. no quick fix info in appInfo, quick fix need to deploy, switch and delete again
113 const auto &qfInfo = appInfo.appQuickFix.deployedAppqfInfo;
114 if (qfInfo.hqfInfos.empty()) {
115 LOG_D(BMS_TAG_DEFAULT, "no quikc fix info in the appInfo and reprocess the quick fix");
116 if (!ReprocessQuickFix(quickFix.second.second, quickFix.first)) {
117 LOG_E(BMS_TAG_DEFAULT, "ReprocessQuickFix failed");
118 }
119 continue;
120 }
121 // 3. appInfo contain quick fix info, there need to check the quick fix info version with the
122 // quick fix file version code
123 LOG_D(BMS_TAG_DEFAULT, "appInfo contains quick fix info");
124 int32_t quickFixVersion = qfInfo.versionCode;
125 if (!ProcessWithBundleHasQuickFixInfo(quickFix.first, quickFix.second.second, quickFixVersion,
126 quickFix.second.first)) {
127 LOG_E(BMS_TAG_DEFAULT, "ProcessWithBundleHasQuickFixInfo failed");
128 }
129 }
130
131 RemoveInvalidDir();
132 LOG_I(BMS_TAG_DEFAULT, "calling RestoreQuickFix successfully");
133 }
134
ProcessQuickFixDir(const std::vector<std::string> & fileDir)135 void QuickFixBootScanner::ProcessQuickFixDir(const std::vector<std::string> &fileDir)
136 {
137 LOG_I(BMS_TAG_DEFAULT, "start to ObtainQuickFixInfo");
138 if (fileDir.empty()) {
139 LOG_W(BMS_TAG_DEFAULT, "no quick fix file");
140 return;
141 }
142 for (const auto &fileStr : fileDir) {
143 LOG_D(BMS_TAG_DEFAULT, "ObtainQuickFixInfo fileStr is %{public}s", fileStr.c_str());
144 size_t underlinePos = fileStr.rfind(Constants::FILE_UNDERLINE);
145 if (underlinePos == std::string::npos) {
146 LOG_E(BMS_TAG_DEFAULT, "ObtainQuickFixInfo failed due to invalid dir");
147 invalidQuickFixDir_.emplace_back(fileStr);
148 continue;
149 }
150 int32_t versionCode;
151 bool ret = StrToInt(fileStr.substr(underlinePos + 1), versionCode);
152 if (!ret) {
153 LOG_E(BMS_TAG_DEFAULT, "ObtainQuickFixInfo failed due to invalid versionCode in dir");
154 invalidQuickFixDir_.emplace_back(fileStr);
155 continue;
156 }
157 LOG_D(BMS_TAG_DEFAULT, "versionCode of the quick fix file is %{public}d", versionCode);
158 size_t firstPos = fileStr.rfind(ServiceConstants::PATH_SEPARATOR);
159 if (firstPos == std::string::npos) {
160 LOG_E(BMS_TAG_DEFAULT, "ObtainQuickFixInfo failed due to invalid dir");
161 invalidQuickFixDir_.emplace_back(fileStr);
162 continue;
163 }
164 size_t secondPos = fileStr.rfind(ServiceConstants::PATH_SEPARATOR, firstPos - 1);
165 if (secondPos == std::string::npos) {
166 LOG_E(BMS_TAG_DEFAULT, "ObtainQuickFixInfo failed due to invalid dir");
167 invalidQuickFixDir_.emplace_back(fileStr);
168 continue;
169 }
170 std::string bundleName = fileStr.substr(secondPos + 1, firstPos - secondPos - 1);
171 LOG_D(BMS_TAG_DEFAULT, "bundleName of the quick fix file is %{public}s", bundleName.c_str());
172 auto bundleIter = quickFixInfoMap_.find(bundleName);
173 if (bundleIter == quickFixInfoMap_.end()) {
174 std::pair<int32_t, std::string> innerPair { versionCode, fileStr };
175 quickFixInfoMap_.emplace(bundleName, innerPair);
176 continue;
177 }
178 if (bundleIter->second.first < versionCode) {
179 invalidQuickFixDir_.emplace_back(bundleIter->second.second);
180 quickFixInfoMap_[bundleName] = { versionCode, fileStr };
181 }
182 }
183 return;
184 }
185
ReprocessQuickFix(const std::string & quickFixPath,const std::string & bundleName) const186 bool QuickFixBootScanner::ReprocessQuickFix(const std::string &quickFixPath, const std::string &bundleName) const
187 {
188 LOG_D(BMS_TAG_DEFAULT, "start to ReprocessQuickFix with bundleName %{public}s", bundleName.c_str());
189 std::string destinationDir = ServiceConstants::HAP_COPY_PATH;
190 destinationDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::SECURITY_QUICK_FIX_PATH +
191 ServiceConstants::PATH_SEPARATOR + bundleName + ServiceConstants::PATH_SEPARATOR;
192 if (!BundleUtil::CreateDir(destinationDir)) {
193 LOG_E(BMS_TAG_DEFAULT, "create dir failed");
194 return false;
195 }
196 if (InstalldClient::GetInstance()->CopyFiles(quickFixPath, destinationDir) != ERR_OK) {
197 LOG_E(BMS_TAG_DEFAULT, "RestoreQuickFix failed due to copy quick fix files failed");
198 return false;
199 }
200
201 std::vector<std::string> pathVec { destinationDir };
202 std::unique_ptr<QuickFixDeployer> deployer = std::make_unique<QuickFixDeployer>(pathVec);
203 auto ret = deployer->Execute();
204 if (ret != ERR_OK) {
205 LOG_E(BMS_TAG_DEFAULT, "deploy failed");
206 return false;
207 }
208 std::unique_ptr<IQuickFix> switcher = std::make_unique<QuickFixSwitcher>(bundleName, true);
209 ret = switcher->Execute();
210 if (ret != ERR_OK) {
211 LOG_E(BMS_TAG_DEFAULT, "switch failed");
212 return false;
213 }
214 std::unique_ptr<IQuickFix> deleter = std::make_unique<QuickFixDeleter>(bundleName);
215 ret = deleter->Execute();
216 if (ret != ERR_OK) {
217 LOG_E(BMS_TAG_DEFAULT, "delete failed");
218 return false;
219 }
220 return true;
221 }
222
GetApplicationInfo(const std::string & bundleName,const std::string & quickFixPath,ApplicationInfo & info)223 bool QuickFixBootScanner::GetApplicationInfo(const std::string &bundleName, const std::string &quickFixPath,
224 ApplicationInfo &info)
225 {
226 if (dataMgr_ == nullptr) {
227 dataMgr_ = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
228 if (dataMgr_ == nullptr) {
229 LOG_E(BMS_TAG_DEFAULT, "dataMgr_ is nullptr");
230 return false;
231 }
232 }
233 if (!dataMgr_->GetApplicationInfo(bundleName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, Constants::ANY_USERID,
234 info)) {
235 LOG_W(BMS_TAG_DEFAULT, "application info is no existed, the quick info file need to be deleted");
236 invalidQuickFixDir_.emplace_back(quickFixPath);
237 return false;
238 }
239 return true;
240 }
241
ProcessWithBundleHasQuickFixInfo(const std::string & bundleName,const std::string & hqfPath,int32_t quickFixVersion,int32_t fileVersion)242 bool QuickFixBootScanner::ProcessWithBundleHasQuickFixInfo(const std::string &bundleName, const std::string &hqfPath,
243 int32_t quickFixVersion, int32_t fileVersion)
244 {
245 if (quickFixVersion == fileVersion) {
246 LOG_D(BMS_TAG_DEFAULT, "same version code between quick fix file and quick fix info");
247 } else if (quickFixVersion < fileVersion) {
248 if (!ReprocessQuickFix(hqfPath, bundleName)) {
249 LOG_E(BMS_TAG_DEFAULT, "ReprocessQuickFix failed");
250 return false;
251 }
252 } else {
253 invalidQuickFixDir_.emplace_back(hqfPath);
254 // remove the quick fix info from memory cache and db
255 InnerBundleInfo innerBundleInfo;
256 if ((dataMgr_ == nullptr) || (!dataMgr_->GetInnerBundleInfo(bundleName, innerBundleInfo))) {
257 LOG_E(BMS_TAG_DEFAULT, "cannot obtain the innerbundleInfo from data mgr");
258 return false;
259 }
260 AppQuickFix appQuickFix;
261 innerBundleInfo.SetAppQuickFix(appQuickFix);
262 innerBundleInfo.SetBundleStatus(InnerBundleInfo::BundleStatus::ENABLED);
263 dataMgr_->EnableBundle(bundleName);
264 if (!dataMgr_->UpdateQuickFixInnerBundleInfo(bundleName, innerBundleInfo)) {
265 LOG_E(BMS_TAG_DEFAULT, "update quickfix innerbundleInfo failed");
266 return false;
267 }
268 LOG_I(BMS_TAG_DEFAULT, "invalid the quick fix file dir and quick fix info needs to be remove");
269 }
270 return true;
271 }
272
RemoveInvalidDir() const273 void QuickFixBootScanner::RemoveInvalidDir() const
274 {
275 // remove invalid dir under install dir
276 if (!invalidQuickFixDir_.empty()) {
277 for_each(invalidQuickFixDir_.begin(), invalidQuickFixDir_.end(), [](const auto &dir) {
278 InstalldClient::GetInstance()->RemoveDir(dir);
279 });
280 }
281 // remove invalid temp install dir
282 std::string tempInstallDir = ServiceConstants::HAP_COPY_PATH + ServiceConstants::PATH_SEPARATOR
283 + ServiceConstants::STREAM_INSTALL_PATH;
284 std::string tempQuickFixDir = ServiceConstants::HAP_COPY_PATH + ServiceConstants::PATH_SEPARATOR
285 + ServiceConstants::QUICK_FIX_PATH;
286 std::string tempSecureInstallDir = ServiceConstants::HAP_COPY_PATH + ServiceConstants::PATH_SEPARATOR +
287 ServiceConstants::SECURITY_STREAM_INSTALL_PATH;
288 std::string tempSecureQuickFixDir = ServiceConstants::HAP_COPY_PATH + ServiceConstants::PATH_SEPARATOR +
289 ServiceConstants::SECURITY_QUICK_FIX_PATH;
290 std::string tempSignatureFileDir = ServiceConstants::HAP_COPY_PATH + ServiceConstants::PATH_SEPARATOR +
291 ServiceConstants::SIGNATURE_FILE_PATH;
292 std::string tempSecureSignatureFileDir = ServiceConstants::HAP_COPY_PATH + ServiceConstants::PATH_SEPARATOR +
293 ServiceConstants::SECURITY_SIGNATURE_FILE_PATH;
294 BundleUtil::DeleteDir(tempInstallDir);
295 BundleUtil::DeleteDir(tempQuickFixDir);
296 BundleUtil::DeleteDir(tempSecureInstallDir);
297 BundleUtil::DeleteDir(tempSecureQuickFixDir);
298 BundleUtil::DeleteDir(tempSignatureFileDir);
299 BundleUtil::DeleteDir(tempSecureSignatureFileDir);
300 }
301 } // AppExecFwk
302 } // OHOS