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_switcher.h"
17
18 #include "app_log_tag_wrapper.h"
19 #include "app_log_wrapper.h"
20 #include "appexecfwk_errors.h"
21 #include "bundle_mgr_service.h"
22 #include "scope_guard.h"
23
24 namespace OHOS {
25 namespace AppExecFwk {
QuickFixSwitcher(const std::string & bundleName,bool enable)26 QuickFixSwitcher::QuickFixSwitcher(const std::string &bundleName, bool enable)
27 : bundleName_(bundleName), enable_(enable)
28 {
29 LOG_I(BMS_TAG_DEFAULT, "enter QuickFixSwitcher");
30 }
31
Execute()32 ErrCode QuickFixSwitcher::Execute()
33 {
34 LOG_I(BMS_TAG_DEFAULT, "start execute");
35 return SwitchQuickFix();
36 }
37
SwitchQuickFix()38 ErrCode QuickFixSwitcher::SwitchQuickFix()
39 {
40 ErrCode result = enable_ ? EnableQuickFix(bundleName_) : DisableQuickFix(bundleName_);
41 if (result != ERR_OK) {
42 LOG_E(BMS_TAG_DEFAULT, "SwitchQuickFix failed");
43 }
44
45 return result;
46 }
47
EnableQuickFix(const std::string & bundleName)48 ErrCode QuickFixSwitcher::EnableQuickFix(const std::string &bundleName)
49 {
50 if (bundleName.empty()) {
51 LOG_E(BMS_TAG_DEFAULT, "EnableQuickFix failed due to empty bundleName");
52 return ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR;
53 }
54 // enable is true, obtain quick fix info from db to replace the current patch
55 if (GetQuickFixDataMgr() != ERR_OK) {
56 LOG_E(BMS_TAG_DEFAULT, "quickFixDataMgr is nullptr");
57 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
58 }
59 InnerAppQuickFix innerAppQuickFix;
60 // 1. query quick fix info from db
61 if (!quickFixDataMgr_->QueryInnerAppQuickFix(bundleName, innerAppQuickFix)) {
62 LOG_E(BMS_TAG_DEFAULT, "no patch in the db");
63 return ERR_BUNDLEMANAGER_QUICK_FIX_NO_PATCH_IN_DATABASE;
64 }
65 // 2. update status in db and start to switch patch
66 if (!quickFixDataMgr_->UpdateQuickFixStatus(QuickFixStatus::SWITCH_ENABLE_START, innerAppQuickFix)) {
67 LOG_E(BMS_TAG_DEFAULT, "update quickfix status %{public}d failed", QuickFixStatus::SWITCH_ENABLE_START);
68 return ERR_BUNDLEMANAGER_QUICK_FIX_INVALID_PATCH_STATUS;
69 }
70 // 3. utilize stateGuard to rollback quick fix in db
71 ScopeGuard stateGuard([&] {
72 innerAppQuickFix.SwitchQuickFix();
73 quickFixDataMgr_->UpdateQuickFixStatus(QuickFixStatus::DEPLOY_END, innerAppQuickFix);
74 });
75
76 innerAppQuickFix.SwitchQuickFix();
77 ErrCode res = InnerSwitchQuickFix(bundleName, innerAppQuickFix, true);
78 if (res != ERR_OK) {
79 LOG_E(BMS_TAG_DEFAULT, "InnerSwitchQuickFix failed");
80 return res;
81 }
82 stateGuard.Dismiss();
83 return ERR_OK;
84 }
85
DisableQuickFix(const std::string & bundleName)86 ErrCode QuickFixSwitcher::DisableQuickFix(const std::string &bundleName)
87 {
88 if (bundleName.empty()) {
89 LOG_E(BMS_TAG_DEFAULT, "DisableQuickFix failed due to empty bundleName");
90 return ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR;
91 }
92 if (GetQuickFixDataMgr() != ERR_OK) {
93 LOG_E(BMS_TAG_DEFAULT, "quickFixDataMgr is nullptr");
94 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
95 }
96 InnerAppQuickFix innerAppQuickFix;
97 // 1. query quick fix info from db, if quick fix info exists, use it to disable quick fix
98 bool isExisted = quickFixDataMgr_->QueryInnerAppQuickFix(bundleName, innerAppQuickFix);
99 if (!isExisted) {
100 LOG_W(BMS_TAG_DEFAULT, "no patch in the db");
101 // 1.1 if quick fix info does not exist, use the temporary quick fix info to mark disable-status in db
102 QuickFixMark fixMark = { .status = QuickFixStatus::DEPLOY_END };
103 AppQuickFix appQuickFix;
104 appQuickFix.bundleName = bundleName;
105 innerAppQuickFix.SetAppQuickFix(appQuickFix);
106 innerAppQuickFix.SetQuickFixMark(fixMark);
107 }
108 // 2. update disable-status in db
109 if (!quickFixDataMgr_->UpdateQuickFixStatus(QuickFixStatus::SWITCH_DISABLE_START, innerAppQuickFix)) {
110 LOG_E(BMS_TAG_DEFAULT, "update quickfix status %{public}d failed", QuickFixStatus::SWITCH_DISABLE_START);
111 return ERR_BUNDLEMANAGER_QUICK_FIX_INVALID_PATCH_STATUS;
112 }
113 // 3. if quick fix exist, stateGuard is utilized to rollback quick fix info in db
114 ScopeGuard stateGuard([&] {
115 if (isExisted) {
116 quickFixDataMgr_->UpdateQuickFixStatus(QuickFixStatus::DEPLOY_END, innerAppQuickFix);
117 } else {
118 quickFixDataMgr_->DeleteInnerAppQuickFix(bundleName);
119 }
120 });
121
122 ErrCode res = InnerSwitchQuickFix(bundleName, innerAppQuickFix, false);
123 if (res != ERR_OK) {
124 LOG_E(BMS_TAG_DEFAULT, "InnerSwitchQuickFix failed %{public}d", res);
125 return res;
126 }
127 stateGuard.Dismiss();
128 return ERR_OK;
129 }
130
InnerSwitchQuickFix(const std::string & bundleName,const InnerAppQuickFix & innerAppQuickFix,bool enable)131 ErrCode QuickFixSwitcher::InnerSwitchQuickFix(const std::string &bundleName, const InnerAppQuickFix &innerAppQuickFix,
132 bool enable)
133 {
134 LOG_D(BMS_TAG_DEFAULT, "InnerSwitchQuickFix start with bundleName: %{public}s", bundleName.c_str());
135 if (bundleName.empty()) {
136 LOG_E(BMS_TAG_DEFAULT, "InnerSwitchQuickFix failed due to empty bundleName");
137 return ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR;
138 }
139
140 if (GetDataMgr() != ERR_OK) {
141 LOG_E(BMS_TAG_DEFAULT, "GetDataMgr failed");
142 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
143 }
144 InnerBundleInfo innerBundleInfo;
145 // 4. obtain innerBundleInfo and enableGuard used to enable bundle which is under disable status
146 if (!dataMgr_->GetInnerBundleInfo(bundleName, innerBundleInfo)) {
147 LOG_E(BMS_TAG_DEFAULT, "cannot obtain the innerbundleInfo from data mgr");
148 return ERR_BUNDLEMANAGER_QUICK_FIX_NOT_EXISTED_BUNDLE_INFO;
149 }
150 ScopeGuard enableGuard([&] { dataMgr_->EnableBundle(bundleName_); });
151 // utilize appQuickFix to rollback
152 AppQuickFix oldAppQuickFix = innerBundleInfo.GetAppQuickFix();
153 if (!enable && oldAppQuickFix.deployedAppqfInfo.hqfInfos.empty()) {
154 LOG_E(BMS_TAG_DEFAULT, "no patch info to be disabled");
155 return ERR_BUNDLEMANAGER_QUICK_FIX_NO_PATCH_INFO_IN_BUNDLE_INFO;
156 }
157 InnerAppQuickFix oldInnerAppQuickFix;
158 // 5. to generate old quick fix info which is about to be deleted from db
159 auto errCode = CreateInnerAppqf(innerBundleInfo, enable, oldInnerAppQuickFix);
160 if (errCode != ERR_OK) {
161 LOG_E(BMS_TAG_DEFAULT, "CreateInnerAppqf failed");
162 return errCode;
163 }
164 // 6. update innerBundleInfo in memory cache and db
165 AppQuickFix newAppQuickFix = innerAppQuickFix.GetAppQuickFix();
166 newAppQuickFix.deployingAppqfInfo = enable ? AppqfInfo() : oldAppQuickFix.deployingAppqfInfo;
167 innerBundleInfo.SetAppQuickFix(newAppQuickFix);
168 innerBundleInfo.SetBundleStatus(InnerBundleInfo::BundleStatus::ENABLED);
169 if (!dataMgr_->UpdateQuickFixInnerBundleInfo(bundleName, innerBundleInfo)) {
170 LOG_E(BMS_TAG_DEFAULT, "update quickfix innerbundleInfo failed");
171 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
172 }
173
174 // 7. utilize innerBundleInfoGuard to rollback inner bundle info in db and memory cache
175 ScopeGuard innerBundleInfoGuard([&] {
176 innerBundleInfo.SetAppQuickFix(oldAppQuickFix);
177 dataMgr_->UpdateQuickFixInnerBundleInfo(bundleName, innerBundleInfo);
178 });
179
180 if (GetQuickFixDataMgr() != ERR_OK) {
181 LOG_E(BMS_TAG_DEFAULT, "GetQuickFixDataMgr failed");
182 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
183 }
184 // 8. update quick fix info status of SWITCH_END
185 auto appQuickFix = oldInnerAppQuickFix.GetAppQuickFix();
186 if (appQuickFix.deployedAppqfInfo.hqfInfos.empty() && appQuickFix.deployingAppqfInfo.hqfInfos.empty()) {
187 quickFixDataMgr_->DeleteInnerAppQuickFix(bundleName);
188 } else {
189 if (!quickFixDataMgr_->UpdateQuickFixStatus(QuickFixStatus::SWITCH_END, oldInnerAppQuickFix)) {
190 LOG_E(BMS_TAG_DEFAULT, "update quickfix status %{public}d failed", QuickFixStatus::SWITCH_END);
191 return ERR_BUNDLEMANAGER_QUICK_FIX_INVALID_PATCH_STATUS;
192 }
193 }
194 innerBundleInfoGuard.Dismiss();
195 return ERR_OK;
196 }
197
CreateInnerAppqf(const InnerBundleInfo & innerBundleInfo,bool enable,InnerAppQuickFix & innerAppQuickFix)198 ErrCode QuickFixSwitcher::CreateInnerAppqf(const InnerBundleInfo &innerBundleInfo,
199 bool enable, InnerAppQuickFix &innerAppQuickFix)
200 {
201 std::string bundleName = innerBundleInfo.GetBundleName();
202 LOG_D(BMS_TAG_DEFAULT, "CreateInnerAppqf start with bundleName: %{public}s", bundleName.c_str());
203
204 InnerAppQuickFix innerAppqf;
205 if (GetQuickFixDataMgr() != ERR_OK) {
206 LOG_E(BMS_TAG_DEFAULT, "quickFixDataMgr_ is nullptr");
207 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
208 }
209 auto res = quickFixDataMgr_->QueryInnerAppQuickFix(bundleName, innerAppqf);
210 // old patch or reload in db will lead failure to create innerAppqf
211 const auto &appQf = innerAppqf.GetAppQuickFix();
212 if (res && !appQf.deployedAppqfInfo.hqfInfos.empty()) {
213 LOG_E(BMS_TAG_DEFAULT, "CreateInnerAppqf failed due to some old patch or hot reload in db");
214 return ERR_BUNDLEMANAGER_QUICK_FIX_OLD_PATCH_OR_HOT_RELOAD_IN_DB;
215 }
216
217 AppQuickFix appQuickFix;
218 appQuickFix.bundleName = bundleName;
219 appQuickFix.versionName = appQf.versionName;
220 appQuickFix.versionCode = appQf.versionCode;
221 appQuickFix.deployedAppqfInfo = innerBundleInfo.GetAppQuickFix().deployedAppqfInfo;
222
223 if (!enable && res) {
224 appQuickFix.deployingAppqfInfo = appQf.deployingAppqfInfo;
225 }
226 QuickFixMark fixMark;
227 fixMark.bundleName = bundleName;
228 fixMark.status = enable ? QuickFixStatus::SWITCH_ENABLE_START : QuickFixStatus::SWITCH_DISABLE_START;
229 innerAppQuickFix.SetAppQuickFix(appQuickFix);
230 innerAppQuickFix.SetQuickFixMark(fixMark);
231 return ERR_OK;
232 }
233
GetQuickFixDataMgr()234 ErrCode QuickFixSwitcher::GetQuickFixDataMgr()
235 {
236 if (quickFixDataMgr_ == nullptr) {
237 quickFixDataMgr_ = DelayedSingleton<QuickFixDataMgr>::GetInstance();
238 if (quickFixDataMgr_ == nullptr) {
239 LOG_E(BMS_TAG_DEFAULT, "quickFixDataMgr_ is nullptr");
240 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
241 }
242 }
243 return ERR_OK;
244 }
245
GetDataMgr()246 ErrCode QuickFixSwitcher::GetDataMgr()
247 {
248 if (dataMgr_ == nullptr) {
249 dataMgr_ = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
250 if (dataMgr_ == nullptr) {
251 LOG_E(BMS_TAG_DEFAULT, "dataMgr_ is nullptr");
252 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
253 }
254 }
255 return ERR_OK;
256 }
257 } // AppExecFwk
258 } // OHOS