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