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