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