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