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_deployer.h"
17
18 #include "app_log_wrapper.h"
19 #include "appexecfwk_errors.h"
20 #include "bundle_constants.h"
21 #include "bundle_mgr_service.h"
22 #include "bundle_util.h"
23 #include "installd_client.h"
24 #include "event_report.h"
25 #include "patch_extractor.h"
26 #include "patch_parser.h"
27 #include "scope_guard.h"
28
29 namespace OHOS {
30 namespace AppExecFwk {
QuickFixDeployer(const std::vector<std::string> & bundleFilePaths)31 QuickFixDeployer::QuickFixDeployer(const std::vector<std::string> &bundleFilePaths) : patchPaths_(bundleFilePaths)
32 {}
33
Execute()34 ErrCode QuickFixDeployer::Execute()
35 {
36 ErrCode ret = DeployQuickFix();
37 if (ret != ERR_OK) {
38 APP_LOGE("QuickFixDeployer errcode %{public}d", ret);
39 }
40 return ret;
41 }
42
DeployQuickFix()43 ErrCode QuickFixDeployer::DeployQuickFix()
44 {
45 if (patchPaths_.empty() || (GetQuickFixDataMgr() != ERR_OK)) {
46 APP_LOGE("DeployQuickFix wrong parms");
47 return ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR;
48 }
49
50 std::vector<std::string> realFilePaths;
51 ErrCode ret = ProcessBundleFilePaths(patchPaths_, realFilePaths);
52 if (ret != ERR_OK) {
53 return ret;
54 }
55 ScopeGuard guardRemovePath([realFilePaths] {
56 for (const auto &path: realFilePaths) {
57 std::string tempPath = path.substr(0, path.rfind(Constants::PATH_SEPARATOR));
58 if (InstalldClient::GetInstance()->RemoveDir(tempPath) != ERR_OK) {
59 APP_LOGE("RemovePatchFile failed path: %{private}s", tempPath.c_str());
60 }
61 }
62 });
63 // parse check multi hqf files, update status DEPLOY_START
64 InnerAppQuickFix newInnerAppQuickFix;
65 InnerAppQuickFix oldInnerAppQuickFix;
66 ret = ToDeployStartStatus(realFilePaths, newInnerAppQuickFix, oldInnerAppQuickFix);
67 if (ret != ERR_OK) {
68 return ret;
69 }
70 // extract diff files, apply diff patch and copy hqf, update status DEPLOY_END
71 ret = ToDeployEndStatus(newInnerAppQuickFix, oldInnerAppQuickFix);
72 if (ret != ERR_OK) {
73 bool isExist = !oldInnerAppQuickFix.GetAppQuickFix().bundleName.empty();
74 if (isExist) {
75 quickFixDataMgr_->SaveInnerAppQuickFix(oldInnerAppQuickFix);
76 } else {
77 quickFixDataMgr_->DeleteInnerAppQuickFix(newInnerAppQuickFix.GetAppQuickFix().bundleName);
78 }
79 return ret;
80 }
81 // remove old deploying patch_versionCode
82 const AppQuickFix &appQuick = oldInnerAppQuickFix.GetAppQuickFix();
83 if (!appQuick.bundleName.empty()) {
84 std::string oldPath = Constants::BUNDLE_CODE_DIR + Constants::PATH_SEPARATOR +
85 appQuick.bundleName + Constants::PATH_SEPARATOR;
86 if (appQuick.deployingAppqfInfo.type == QuickFixType::HOT_RELOAD) {
87 oldPath += Constants::HOT_RELOAD_PATH + std::to_string(appQuick.deployingAppqfInfo.versionCode);
88 } else {
89 oldPath += Constants::PATCH_PATH + std::to_string(appQuick.deployingAppqfInfo.versionCode);
90 }
91 if (InstalldClient::GetInstance()->RemoveDir(oldPath)) {
92 APP_LOGE("delete %{private}s failed", oldPath.c_str());
93 }
94 }
95 return ERR_OK;
96 }
97
ToDeployStartStatus(const std::vector<std::string> & bundleFilePaths,InnerAppQuickFix & newInnerAppQuickFix,InnerAppQuickFix & oldInnerAppQuickFix)98 ErrCode QuickFixDeployer::ToDeployStartStatus(const std::vector<std::string> &bundleFilePaths,
99 InnerAppQuickFix &newInnerAppQuickFix, InnerAppQuickFix &oldInnerAppQuickFix)
100 {
101 APP_LOGI("ToDeployStartStatus start.");
102 if (GetQuickFixDataMgr() != ERR_OK) {
103 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
104 }
105 std::unordered_map<std::string, AppQuickFix> infos;
106 // parse and check multi app quick fix info
107 ErrCode ret = ParseAndCheckAppQuickFixInfos(bundleFilePaths, infos);
108 if (ret != ERR_OK) {
109 return ret;
110 }
111 const AppQuickFix &appQuickFix = infos.begin()->second;
112 bool isExist = quickFixDataMgr_->QueryInnerAppQuickFix(appQuickFix.bundleName, oldInnerAppQuickFix);
113 const QuickFixMark &mark = oldInnerAppQuickFix.GetQuickFixMark();
114 if (isExist && (mark.status != QuickFixStatus::DEPLOY_START) && (mark.status != QuickFixStatus::DEPLOY_END)) {
115 APP_LOGE("error: wrong quick fix status, now status : %{public}d", mark.status);
116 return ERR_BUNDLEMANAGER_QUICK_FIX_INVALID_PATCH_STATUS;
117 }
118 const AppQuickFix &oldAppQuickFix = oldInnerAppQuickFix.GetAppQuickFix();
119 // exist and type same need to check version code
120 if (isExist && (appQuickFix.deployingAppqfInfo.type == oldAppQuickFix.deployingAppqfInfo.type)) {
121 // check current app quick fix version code
122 ret = CheckPatchVersionCode(appQuickFix, oldAppQuickFix);
123 if (ret != ERR_OK) {
124 return ret;
125 }
126 }
127 // check bundleName exist
128 BundleInfo bundleInfo;
129 ret = GetBundleInfo(appQuickFix.bundleName, bundleInfo);
130 if (ret != ERR_OK) {
131 APP_LOGE("GetBundleInfo failed, bundleName: %{public}s", appQuickFix.bundleName.c_str());
132 return ret;
133 }
134 // check with installed bundle
135 if (appQuickFix.deployingAppqfInfo.type == QuickFixType::PATCH) {
136 ret = ProcessPatchDeployStart(bundleFilePaths, bundleInfo, infos);
137 } else if (appQuickFix.deployingAppqfInfo.type == QuickFixType::HOT_RELOAD) {
138 ret = ProcessHotReloadDeployStart(bundleInfo, appQuickFix);
139 } else {
140 ret = ERR_BUNDLEMANAGER_QUICK_FIX_UNKNOWN_QUICK_FIX_TYPE;
141 }
142 if (ret != ERR_OK) {
143 return ret;
144 }
145 // convert to InnerAppQuickFix
146 ret = ToInnerAppQuickFix(infos, oldInnerAppQuickFix, newInnerAppQuickFix);
147 if (ret != ERR_OK) {
148 return ret;
149 }
150 // save infos and update status DEPLOY_START
151 ret = SaveAppQuickFix(newInnerAppQuickFix);
152 if (ret != ERR_OK) {
153 APP_LOGE("SaveAppQuickFix failed, errcode: %{public}d", ret);
154 return ret;
155 }
156 APP_LOGI("ToDeployStartStatus end.");
157 return ERR_OK;
158 }
159
ToDeployQuickFixResult(const AppQuickFix & appQuickFix)160 void QuickFixDeployer::ToDeployQuickFixResult(const AppQuickFix &appQuickFix)
161 {
162 APP_LOGD("ToDeployQuickFixResult start.");
163 deployQuickFixResult_.bundleName = appQuickFix.bundleName;
164 deployQuickFixResult_.bundleVersionCode = appQuickFix.versionCode;
165 deployQuickFixResult_.patchVersionCode = appQuickFix.deployingAppqfInfo.versionCode;
166 deployQuickFixResult_.type = appQuickFix.deployingAppqfInfo.type;
167 deployQuickFixResult_.isSoContained = HasNativeSoInBundle(appQuickFix);
168 deployQuickFixResult_.moduleNames.clear();
169 for (const auto &hqf : appQuickFix.deployingAppqfInfo.hqfInfos) {
170 deployQuickFixResult_.moduleNames.emplace_back(hqf.moduleName);
171 }
172 APP_LOGD("ToDeployQuickFixResult end.");
173 }
174
ProcessPatchDeployStart(const std::vector<std::string> bundleFilePaths,const BundleInfo & bundleInfo,std::unordered_map<std::string,AppQuickFix> & infos)175 ErrCode QuickFixDeployer::ProcessPatchDeployStart(
176 const std::vector<std::string> bundleFilePaths,
177 const BundleInfo &bundleInfo,
178 std::unordered_map<std::string, AppQuickFix> &infos)
179 {
180 APP_LOGI("ProcessPatchDeployStart start.");
181 if (infos.empty()) {
182 APP_LOGE("error: appQuickFix infos is empty");
183 return ERR_BUNDLEMANAGER_QUICK_FIX_PROFILE_PARSE_FAILED;
184 }
185 QuickFixChecker checker;
186 // check multiple cpuAbi and native library path
187 ErrCode ret = checker.CheckMultiNativeSo(infos);
188 if (ret != ERR_OK) {
189 APP_LOGE("ProcessPatchDeployStart check native so failed");
190 return ret;
191 }
192 // parse signature info
193 std::vector<Security::Verify::HapVerifyResult> hapVerifyRes;
194 ret = checker.CheckMultipleHqfsSignInfo(bundleFilePaths, hapVerifyRes);
195 if (ret != ERR_OK) {
196 APP_LOGE("ProcessPatchDeployStart check check multiple hqfs signInfo failed");
197 return ret;
198 }
199 if (hapVerifyRes.empty()) {
200 APP_LOGE("error: appQuickFix hapVerifyRes is empty");
201 return ERR_APPEXECFWK_INSTALL_FAILED_INCOMPATIBLE_SIGNATURE;
202 }
203 const auto &provisionInfo = hapVerifyRes[0].GetProvisionInfo();
204 const AppQuickFix &appQuickFix = infos.begin()->second;
205 // check with installed bundle, signature info, bundleName, versionCode
206 ret = checker.CheckPatchWithInstalledBundle(appQuickFix, bundleInfo, provisionInfo);
207 if (ret != ERR_OK) {
208 APP_LOGE("check AppQuickFixInfos with installed bundle failed, errcode : %{public}d", ret);
209 return ret;
210 }
211 appDistributionType_ = checker.GetAppDistributionType(provisionInfo.distributionType);
212 APP_LOGI("ProcessPatchDeployStart end.");
213 return ERR_OK;
214 }
215
ProcessHotReloadDeployStart(const BundleInfo & bundleInfo,const AppQuickFix & appQuickFix)216 ErrCode QuickFixDeployer::ProcessHotReloadDeployStart(
217 const BundleInfo &bundleInfo,
218 const AppQuickFix &appQuickFix)
219 {
220 APP_LOGI("ProcessHotReloadDeployStart start.");
221 QuickFixChecker checker;
222 ErrCode ret = checker.CheckHotReloadWithInstalledBundle(appQuickFix, bundleInfo);
223 if (ret != ERR_OK) {
224 APP_LOGE("check AppQuickFixInfos with installed bundle failed");
225 return ret;
226 }
227 APP_LOGI("ProcessHotReloadDeployStart end.");
228 return ERR_OK;
229 }
230
ToDeployEndStatus(InnerAppQuickFix & newInnerAppQuickFix,const InnerAppQuickFix & oldInnerAppQuickFix)231 ErrCode QuickFixDeployer::ToDeployEndStatus(InnerAppQuickFix &newInnerAppQuickFix,
232 const InnerAppQuickFix &oldInnerAppQuickFix)
233 {
234 APP_LOGI("ToDeployEndStatus start.");
235 if ((GetQuickFixDataMgr() != ERR_OK)) {
236 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
237 }
238 // create patch path
239 AppQuickFix newQuickFix = newInnerAppQuickFix.GetAppQuickFix();
240 std::string newPatchPath;
241 ScopeGuard guardRemovePatchPath([&newPatchPath] {
242 InstalldClient::GetInstance()->RemoveDir(newPatchPath);
243 });
244 ErrCode ret = ERR_OK;
245 if (newQuickFix.deployingAppqfInfo.type == QuickFixType::PATCH) {
246 // extract diff files and apply diff patch
247 ret = ProcessPatchDeployEnd(newQuickFix, newPatchPath);
248 } else if (newQuickFix.deployingAppqfInfo.type == QuickFixType::HOT_RELOAD) {
249 ret = ProcessHotReloadDeployEnd(newQuickFix, newPatchPath);
250 } else {
251 APP_LOGE("error: unknown QuickFixType");
252 return ERR_BUNDLEMANAGER_QUICK_FIX_PROFILE_PARSE_FAILED;
253 }
254 if (ret != ERR_OK) {
255 APP_LOGE("Process Patch or HotReload DeployEnd failed, bundleName:%{public}s",
256 newQuickFix.bundleName.c_str());
257 return ret;
258 }
259
260 // if so files exist, library path add patch_versionCode;
261 // if so files not exist, modify library path to empty.
262 ProcessNativeLibraryPath(newPatchPath, newInnerAppQuickFix);
263
264 // move hqf files to new patch path
265 ret = MoveHqfFiles(newInnerAppQuickFix, newPatchPath);
266 if (ret != ERR_OK) {
267 APP_LOGE("error MoveHqfFiles failed, bundleName: %{public}s", newQuickFix.bundleName.c_str());
268 return ret;
269 }
270 // save and update status DEPLOY_END
271 ret = SaveAppQuickFix(newInnerAppQuickFix);
272 if (ret != ERR_OK) {
273 return ret;
274 }
275 ToDeployQuickFixResult(newQuickFix);
276 ret = SaveToInnerBundleInfo(newInnerAppQuickFix);
277 if (ret != ERR_OK) {
278 APP_LOGE("error: bundleName %{public}s update deploying quick fix info to innerBundleInfo failed",
279 newQuickFix.bundleName.c_str());
280 return ret;
281 }
282 guardRemovePatchPath.Dismiss();
283 APP_LOGI("ToDeployEndStatus end.");
284 return ERR_OK;
285 }
286
ProcessNativeLibraryPath(const std::string & patchPath,InnerAppQuickFix & innerAppQuickFix)287 void QuickFixDeployer::ProcessNativeLibraryPath(const std::string &patchPath, InnerAppQuickFix &innerAppQuickFix)
288 {
289 AppQuickFix appQuickFix = innerAppQuickFix.GetAppQuickFix();
290 if (!appQuickFix.deployingAppqfInfo.nativeLibraryPath.empty()) {
291 std::string nativeLibraryPath = appQuickFix.deployingAppqfInfo.nativeLibraryPath;
292 ProcessNativeLibraryPath(patchPath, innerAppQuickFix, nativeLibraryPath);
293 appQuickFix.deployingAppqfInfo.nativeLibraryPath = nativeLibraryPath;
294 }
295
296 for (auto &hqfInfo : appQuickFix.deployingAppqfInfo.hqfInfos) {
297 if (!hqfInfo.nativeLibraryPath.empty()) {
298 std::string nativeLibraryPath = hqfInfo.nativeLibraryPath;
299 ProcessNativeLibraryPath(patchPath, innerAppQuickFix, nativeLibraryPath);
300 hqfInfo.nativeLibraryPath = nativeLibraryPath;
301 }
302 }
303
304 innerAppQuickFix.SetAppQuickFix(appQuickFix);
305 }
306
ProcessNativeLibraryPath(const std::string & patchPath,const InnerAppQuickFix & innerAppQuickFix,std::string & nativeLibraryPath)307 void QuickFixDeployer::ProcessNativeLibraryPath(
308 const std::string &patchPath, const InnerAppQuickFix &innerAppQuickFix, std::string &nativeLibraryPath)
309 {
310 bool isSoExist = false;
311 auto libraryPath = nativeLibraryPath;
312 std::string soPath = patchPath + Constants::PATH_SEPARATOR + libraryPath;
313 if (InstalldClient::GetInstance()->IsExistDir(soPath, isSoExist) != ERR_OK) {
314 APP_LOGE("ProcessNativeLibraryPath InstalldClient IsExistDir(%{public}s) failed", soPath.c_str());
315 return;
316 }
317
318 AppQuickFix appQuickFix = innerAppQuickFix.GetAppQuickFix();
319 if (isSoExist) {
320 nativeLibraryPath = Constants::PATCH_PATH +
321 std::to_string(appQuickFix.deployingAppqfInfo.versionCode) + Constants::PATH_SEPARATOR + libraryPath;
322 } else {
323 APP_LOGI("So(%{public}s) is not exist and set nativeLibraryPath(%{public}s) empty",
324 soPath.c_str(), nativeLibraryPath.c_str());
325 nativeLibraryPath.clear();
326 }
327 }
328
ProcessPatchDeployEnd(const AppQuickFix & appQuickFix,std::string & patchPath)329 ErrCode QuickFixDeployer::ProcessPatchDeployEnd(const AppQuickFix &appQuickFix, std::string &patchPath)
330 {
331 patchPath = Constants::BUNDLE_CODE_DIR + Constants::PATH_SEPARATOR + appQuickFix.bundleName +
332 Constants::PATH_SEPARATOR + Constants::PATCH_PATH +
333 std::to_string(appQuickFix.deployingAppqfInfo.versionCode);
334 ErrCode ret = InstalldClient::GetInstance()->CreateBundleDir(patchPath);
335 if (ret != ERR_OK) {
336 APP_LOGE("error: creat patch path failed, errcode %{public}d", ret);
337 return ERR_BUNDLEMANAGER_QUICK_FIX_CREATE_PATCH_PATH_FAILED;
338 }
339 BundleInfo bundleInfo;
340 ret = GetBundleInfo(appQuickFix.bundleName, bundleInfo);
341 if (ret != ERR_OK) {
342 return ret;
343 }
344 std::string oldSoPath = Constants::HAP_COPY_PATH + Constants::PATH_SEPARATOR +
345 appQuickFix.bundleName + Constants::TMP_SUFFIX + Constants::LIBS;
346 ScopeGuard guardRemoveOldSoPath([oldSoPath] {InstalldClient::GetInstance()->RemoveDir(oldSoPath);});
347
348 auto &appQfInfo = appQuickFix.deployingAppqfInfo;
349 for (const auto &hqf : appQfInfo.hqfInfos) {
350 // if hap has no so file then continue
351 std::string tmpSoPath = oldSoPath;
352 if (!ExtractSoFiles(bundleInfo, hqf.moduleName, tmpSoPath)) {
353 APP_LOGW("module:%{public}s has no so file", hqf.moduleName.c_str());
354 continue;
355 }
356 auto result = ProcessApplyDiffPatch(appQuickFix, hqf, tmpSoPath, patchPath);
357 if (result != ERR_OK) {
358 APP_LOGE("bundleName: %{public}s ProcessApplyDiffPatch failed.", appQuickFix.bundleName.c_str());
359 return result;
360 }
361 }
362 return ERR_OK;
363 }
364
ProcessHotReloadDeployEnd(const AppQuickFix & appQuickFix,std::string & patchPath)365 ErrCode QuickFixDeployer::ProcessHotReloadDeployEnd(const AppQuickFix &appQuickFix, std::string &patchPath)
366 {
367 patchPath = Constants::BUNDLE_CODE_DIR + Constants::PATH_SEPARATOR + appQuickFix.bundleName +
368 Constants::PATH_SEPARATOR + Constants::HOT_RELOAD_PATH +
369 std::to_string(appQuickFix.deployingAppqfInfo.versionCode);
370 ErrCode ret = InstalldClient::GetInstance()->CreateBundleDir(patchPath);
371 if (ret != ERR_OK) {
372 APP_LOGE("error: creat hotreload path failed, errcode %{public}d", ret);
373 return ERR_BUNDLEMANAGER_QUICK_FIX_CREATE_PATCH_PATH_FAILED;
374 }
375 return ERR_OK;
376 }
377
ParseAndCheckAppQuickFixInfos(const std::vector<std::string> & bundleFilePaths,std::unordered_map<std::string,AppQuickFix> & infos)378 ErrCode QuickFixDeployer::ParseAndCheckAppQuickFixInfos(
379 const std::vector<std::string> &bundleFilePaths,
380 std::unordered_map<std::string, AppQuickFix> &infos)
381 {
382 // parse hqf file to AppQuickFix
383 PatchParser patchParser;
384 ErrCode ret = patchParser.ParsePatchInfo(bundleFilePaths, infos);
385 if ((ret != ERR_OK) || infos.empty()) {
386 APP_LOGE("parse AppQuickFixFiles failed, errcode %{public}d", ret);
387 return ERR_BUNDLEMANAGER_QUICK_FIX_PROFILE_PARSE_FAILED;
388 }
389
390 ResetNativeSoAttrs(infos);
391 QuickFixChecker checker;
392 // check multiple AppQuickFix
393 ret = checker.CheckAppQuickFixInfos(infos);
394 if (ret != ERR_OK) {
395 APP_LOGE("check AppQuickFixInfos failed");
396 return ret;
397 }
398 const QuickFixType &quickFixType = infos.begin()->second.deployingAppqfInfo.type;
399 if (quickFixType == QuickFixType::UNKNOWN) {
400 APP_LOGE("error unknown quick fix type");
401 return ERR_BUNDLEMANAGER_QUICK_FIX_UNKNOWN_QUICK_FIX_TYPE;
402 }
403 // hqf file path
404 for (auto iter = infos.begin(); iter != infos.end(); ++iter) {
405 if (!iter->second.deployingAppqfInfo.hqfInfos.empty()) {
406 iter->second.deployingAppqfInfo.hqfInfos[0].hqfFilePath = iter->first;
407 } else {
408 return ERR_BUNDLEMANAGER_QUICK_FIX_PROFILE_PARSE_FAILED;
409 }
410 }
411 return ERR_OK;
412 }
413
ResetNativeSoAttrs(std::unordered_map<std::string,AppQuickFix> & infos)414 void QuickFixDeployer::ResetNativeSoAttrs(std::unordered_map<std::string, AppQuickFix> &infos)
415 {
416 for (auto &info : infos) {
417 ResetNativeSoAttrs(info.second);
418 }
419 }
420
ResetNativeSoAttrs(AppQuickFix & appQuickFix)421 void QuickFixDeployer::ResetNativeSoAttrs(AppQuickFix &appQuickFix)
422 {
423 auto &appqfInfo = appQuickFix.deployingAppqfInfo;
424 if (appqfInfo.hqfInfos.size() != 1) {
425 APP_LOGW("The number of hqfInfos is not one.");
426 return;
427 }
428
429 bool isLibIsolated = IsLibIsolated(appQuickFix.bundleName, appqfInfo.hqfInfos[0].moduleName);
430 if (!isLibIsolated) {
431 APP_LOGW("Lib is not isolated.");
432 return;
433 }
434
435 appqfInfo.hqfInfos[0].cpuAbi = appqfInfo.cpuAbi;
436 appqfInfo.hqfInfos[0].nativeLibraryPath =
437 appqfInfo.hqfInfos[0].moduleName + Constants::PATH_SEPARATOR + appqfInfo.nativeLibraryPath;
438 appqfInfo.nativeLibraryPath.clear();
439 }
440
IsLibIsolated(const std::string & bundleName,const std::string & moduleName)441 bool QuickFixDeployer::IsLibIsolated(
442 const std::string &bundleName, const std::string &moduleName)
443 {
444 InnerBundleInfo innerBundleInfo;
445 if (!FetchInnerBundleInfo(bundleName, innerBundleInfo)) {
446 APP_LOGE("Fetch bundleInfo(%{public}s) failed.", bundleName.c_str());
447 return false;
448 }
449
450 return innerBundleInfo.IsLibIsolated(moduleName);
451 }
452
FetchInnerBundleInfo(const std::string & bundleName,InnerBundleInfo & innerBundleInfo)453 bool QuickFixDeployer::FetchInnerBundleInfo(
454 const std::string &bundleName, InnerBundleInfo &innerBundleInfo)
455 {
456 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
457 if (dataMgr == nullptr) {
458 APP_LOGE("error dataMgr is nullptr");
459 return false;
460 }
461
462 if (!dataMgr->FetchInnerBundleInfo(bundleName, innerBundleInfo)) {
463 APP_LOGE("Fetch bundleInfo(%{public}s) failed.", bundleName.c_str());
464 return false;
465 }
466
467 return true;
468 }
469
FetchPatchNativeSoAttrs(const AppqfInfo & appqfInfo,const HqfInfo hqfInfo,bool isLibIsolated,std::string & nativeLibraryPath,std::string & cpuAbi)470 bool QuickFixDeployer::FetchPatchNativeSoAttrs(const AppqfInfo &appqfInfo,
471 const HqfInfo hqfInfo, bool isLibIsolated, std::string &nativeLibraryPath, std::string &cpuAbi)
472 {
473 if (isLibIsolated) {
474 nativeLibraryPath = hqfInfo.nativeLibraryPath;
475 cpuAbi = hqfInfo.cpuAbi;
476 } else {
477 nativeLibraryPath = appqfInfo.nativeLibraryPath;
478 cpuAbi = appqfInfo.cpuAbi;
479 }
480
481 return !nativeLibraryPath.empty();
482 }
483
HasNativeSoInBundle(const AppQuickFix & appQuickFix)484 bool QuickFixDeployer::HasNativeSoInBundle(const AppQuickFix &appQuickFix)
485 {
486 if (!appQuickFix.deployingAppqfInfo.nativeLibraryPath.empty()) {
487 return true;
488 }
489
490 for (const auto &hqfInfo : appQuickFix.deployingAppqfInfo.hqfInfos) {
491 if (!hqfInfo.nativeLibraryPath.empty()) {
492 return true;
493 }
494 }
495
496 return false;
497 }
498
GetBundleInfo(const std::string & bundleName,BundleInfo & bundleInfo)499 ErrCode QuickFixDeployer::GetBundleInfo(const std::string &bundleName, BundleInfo &bundleInfo)
500 {
501 std::shared_ptr<BundleMgrService> bms = DelayedSingleton<BundleMgrService>::GetInstance();
502 if (bms == nullptr) {
503 APP_LOGE("error: bms is nullptr");
504 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
505 }
506 std::shared_ptr<BundleDataMgr> dataMgr = bms->GetDataMgr();
507 if (dataMgr == nullptr) {
508 APP_LOGE("error: dataMgr is nullptr");
509 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
510 }
511 // check bundleName is exists
512 if (!dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT,
513 bundleInfo, Constants::ANY_USERID)) {
514 APP_LOGE("error: GetBundleInfo failed, bundleName: %{public}s not exist", bundleName.c_str());
515 return ERR_BUNDLEMANAGER_QUICK_FIX_BUNDLE_NAME_NOT_EXIST;
516 }
517 return ERR_OK;
518 }
519
ToInnerAppQuickFix(const std::unordered_map<std::string,AppQuickFix> infos,const InnerAppQuickFix & oldInnerAppQuickFix,InnerAppQuickFix & newInnerAppQuickFix)520 ErrCode QuickFixDeployer::ToInnerAppQuickFix(const std::unordered_map<std::string, AppQuickFix> infos,
521 const InnerAppQuickFix &oldInnerAppQuickFix, InnerAppQuickFix &newInnerAppQuickFix)
522 {
523 APP_LOGD("ToInnerAppQuickFix start");
524 if (infos.empty()) {
525 APP_LOGE("error: appQuickFix is empty");
526 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
527 }
528 AppQuickFix oldAppQuickFix = oldInnerAppQuickFix.GetAppQuickFix();
529 AppQuickFix appQuickFix = infos.begin()->second;
530 // copy deployed app qf info
531 appQuickFix.deployedAppqfInfo = oldAppQuickFix.deployedAppqfInfo;
532 newInnerAppQuickFix.SetAppQuickFix(appQuickFix);
533 QuickFixMark mark;
534 mark.bundleName = appQuickFix.bundleName;
535 mark.status = QuickFixStatus::DEPLOY_START;
536 for (auto iter = infos.begin(); iter != infos.end(); ++iter) {
537 const auto &quickFix = iter->second;
538 // hqfInfos will not be empty, it has been judged before.
539 const std::string &moduleName = quickFix.deployingAppqfInfo.hqfInfos[0].moduleName;
540 if (!newInnerAppQuickFix.AddHqfInfo(quickFix)) {
541 APP_LOGE("error: appQuickFix add hqf moduleName: %{public}s failed", moduleName.c_str());
542 return ERR_BUNDLEMANAGER_QUICK_FIX_ADD_HQF_FAILED;
543 }
544 }
545 newInnerAppQuickFix.SetQuickFixMark(mark);
546 APP_LOGD("ToInnerAppQuickFix end");
547 return ERR_OK;
548 }
549
CheckPatchVersionCode(const AppQuickFix & newAppQuickFix,const AppQuickFix & oldAppQuickFix)550 ErrCode QuickFixDeployer::CheckPatchVersionCode(
551 const AppQuickFix &newAppQuickFix,
552 const AppQuickFix &oldAppQuickFix)
553 {
554 const AppqfInfo &newInfo = newAppQuickFix.deployingAppqfInfo;
555 const AppqfInfo &oldInfoDeployed = oldAppQuickFix.deployedAppqfInfo;
556 const AppqfInfo &oldInfoDeploying = oldAppQuickFix.deployingAppqfInfo;
557 if ((newInfo.versionCode > oldInfoDeployed.versionCode) &&
558 (newInfo.versionCode > oldInfoDeploying.versionCode)) {
559 return ERR_OK;
560 }
561 APP_LOGE("CheckPatchVersionCode failed, version code should be greater than the original");
562 return ERR_BUNDLEMANAGER_QUICK_FIX_VERSION_CODE_ERROR;
563 }
564
SaveAppQuickFix(const InnerAppQuickFix & innerAppQuickFix)565 ErrCode QuickFixDeployer::SaveAppQuickFix(const InnerAppQuickFix &innerAppQuickFix)
566 {
567 if ((GetQuickFixDataMgr() != ERR_OK)) {
568 APP_LOGE("error: quickFixDataMgr_ is nullptr");
569 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
570 }
571 if (!quickFixDataMgr_->SaveInnerAppQuickFix(innerAppQuickFix)) {
572 APP_LOGE("bundleName: %{public}s, inner app quick fix save failed",
573 innerAppQuickFix.GetAppQuickFix().bundleName.c_str());
574 return ERR_BUNDLEMANAGER_QUICK_FIX_SAVE_APP_QUICK_FIX_FAILED;
575 }
576 return ERR_OK;
577 }
578
MoveHqfFiles(InnerAppQuickFix & innerAppQuickFix,const std::string & targetPath)579 ErrCode QuickFixDeployer::MoveHqfFiles(InnerAppQuickFix &innerAppQuickFix, const std::string &targetPath)
580 {
581 APP_LOGD("MoveHqfFiles start.");
582 if (targetPath.empty() || (GetQuickFixDataMgr() != ERR_OK)) {
583 APP_LOGE("MoveHqfFiles params error");
584 return ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR;
585 }
586 QuickFixMark mark = innerAppQuickFix.GetQuickFixMark();
587 AppQuickFix appQuickFix = innerAppQuickFix.GetAppQuickFix();
588 std::string path = targetPath;
589 if (path.back() != Constants::FILE_SEPARATOR_CHAR) {
590 path.push_back(Constants::FILE_SEPARATOR_CHAR);
591 }
592 for (HqfInfo &info : appQuickFix.deployingAppqfInfo.hqfInfos) {
593 if (info.hqfFilePath.empty()) {
594 APP_LOGE("error hapFilePath is empty");
595 return ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR;
596 }
597 std::string realPath = path + info.moduleName + Constants::QUICK_FIX_FILE_SUFFIX;
598 ErrCode ret = InstalldClient::GetInstance()->CopyFile(info.hqfFilePath, realPath);
599 if (ret != ERR_OK) {
600 APP_LOGE("error CopyFile failed, errcode: %{public}d", ret);
601 return ERR_BUNDLEMANAGER_QUICK_FIX_MOVE_PATCH_FILE_FAILED;
602 }
603 info.hqfFilePath = realPath;
604 }
605 mark.status = QuickFixStatus::DEPLOY_END;
606 innerAppQuickFix.SetQuickFixMark(mark);
607 innerAppQuickFix.SetAppQuickFix(appQuickFix);
608 APP_LOGD("MoveHqfFiles end.");
609 return ERR_OK;
610 }
611
GetDeployQuickFixResult() const612 DeployQuickFixResult QuickFixDeployer::GetDeployQuickFixResult() const
613 {
614 return deployQuickFixResult_;
615 }
616
GetQuickFixDataMgr()617 ErrCode QuickFixDeployer::GetQuickFixDataMgr()
618 {
619 if (quickFixDataMgr_ == nullptr) {
620 quickFixDataMgr_ = DelayedSingleton<QuickFixDataMgr>::GetInstance();
621 if (quickFixDataMgr_ == nullptr) {
622 APP_LOGE("error: quickFixDataMgr_ is nullptr");
623 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
624 }
625 }
626 return ERR_OK;
627 }
628
SaveToInnerBundleInfo(const InnerAppQuickFix & newInnerAppQuickFix)629 ErrCode QuickFixDeployer::SaveToInnerBundleInfo(const InnerAppQuickFix &newInnerAppQuickFix)
630 {
631 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
632 if (dataMgr == nullptr) {
633 APP_LOGE("error dataMgr is nullptr");
634 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
635 }
636 const std::string &bundleName = newInnerAppQuickFix.GetAppQuickFix().bundleName;
637 InnerBundleInfo innerBundleInfo;
638 // obtain innerBundleInfo and enableGuard used to enable bundle which is under disable status
639 if (!dataMgr->GetInnerBundleInfo(bundleName, innerBundleInfo)) {
640 APP_LOGE("cannot obtain the innerbundleInfo from data mgr");
641 return ERR_BUNDLEMANAGER_QUICK_FIX_NOT_EXISTED_BUNDLE_INFO;
642 }
643 ScopeGuard enableGuard([&bundleName, &dataMgr] { dataMgr->EnableBundle(bundleName); });
644 AppQuickFix appQuickFix = newInnerAppQuickFix.GetAppQuickFix();
645 appQuickFix.deployedAppqfInfo = innerBundleInfo.GetAppQuickFix().deployedAppqfInfo;
646 // add apply quick fix frequency
647 innerBundleInfo.AddApplyQuickFixFrequency();
648 innerBundleInfo.SetAppQuickFix(appQuickFix);
649 innerBundleInfo.SetBundleStatus(InnerBundleInfo::BundleStatus::ENABLED);
650 if (!dataMgr->UpdateQuickFixInnerBundleInfo(bundleName, innerBundleInfo)) {
651 APP_LOGE("update quickfix innerbundleInfo failed");
652 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
653 }
654 // send quick fix data
655 SendQuickFixSystemEvent(innerBundleInfo);
656 return ERR_OK;
657 }
658
ProcessBundleFilePaths(const std::vector<std::string> & bundleFilePaths,std::vector<std::string> & realFilePaths)659 ErrCode QuickFixDeployer::ProcessBundleFilePaths(const std::vector<std::string> &bundleFilePaths,
660 std::vector<std::string> &realFilePaths)
661 {
662 for (const auto &path : bundleFilePaths) {
663 if (path.find(Constants::RELATIVE_PATH) != std::string::npos) {
664 APP_LOGE("ProcessBundleFilePaths path is illegal.");
665 return ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR;
666 }
667 if (path.find(Constants::HAP_COPY_PATH + Constants::PATH_SEPARATOR +
668 Constants::SECURITY_QUICK_FIX_PATH + Constants::PATH_SEPARATOR) != 0) {
669 APP_LOGE("ProcessBundleFilePaths path is illegal.");
670 return ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR;
671 }
672 }
673 ErrCode ret = BundleUtil::CheckFilePath(bundleFilePaths, realFilePaths);
674 if (ret != ERR_OK) {
675 APP_LOGE("ProcessBundleFilePaths CheckFilePath failed.");
676 return ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR;
677 }
678 for (const auto &path : realFilePaths) {
679 if (!BundleUtil::CheckFileType(path, Constants::QUICK_FIX_FILE_SUFFIX)) {
680 APP_LOGE("ProcessBundleFilePaths CheckFileType failed.");
681 return ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR;
682 }
683 }
684 return ERR_OK;
685 }
686
SendQuickFixSystemEvent(const InnerBundleInfo & innerBundleInfo)687 void QuickFixDeployer::SendQuickFixSystemEvent(const InnerBundleInfo &innerBundleInfo)
688 {
689 EventInfo sysEventInfo;
690 sysEventInfo.errCode = ERR_OK;
691 sysEventInfo.bundleName = innerBundleInfo.GetBundleName();
692 sysEventInfo.appDistributionType = appDistributionType_;
693 for (const auto &hqfInfo : innerBundleInfo.GetAppQuickFix().deployingAppqfInfo.hqfInfos) {
694 sysEventInfo.filePath.push_back(hqfInfo.hqfFilePath);
695 sysEventInfo.hashValue.push_back(hqfInfo.hapSha256);
696 }
697 sysEventInfo.applyQuickFixFrequency = innerBundleInfo.GetApplyQuickFixFrequency();
698 EventReport::SendBundleSystemEvent(BundleEventType::QUICK_FIX, sysEventInfo);
699 }
700
ExtractSoFiles(const BundleInfo & bundleInfo,const std::string & moduleName,std::string & tmpSoPath)701 bool QuickFixDeployer::ExtractSoFiles(
702 const BundleInfo &bundleInfo,
703 const std::string &moduleName,
704 std::string &tmpSoPath)
705 {
706 auto iter = std::find_if(std::begin(bundleInfo.hapModuleInfos), std::end(bundleInfo.hapModuleInfos),
707 [&moduleName](const HapModuleInfo &info) {
708 return info.moduleName == moduleName;
709 });
710 if (iter == bundleInfo.hapModuleInfos.end()) {
711 return false;
712 }
713 std::string cpuAbi = bundleInfo.applicationInfo.cpuAbi;
714 std::string nativeLibraryPath = bundleInfo.applicationInfo.nativeLibraryPath;
715 if (!iter->nativeLibraryPath.empty()) {
716 cpuAbi = iter->cpuAbi;
717 nativeLibraryPath = iter->nativeLibraryPath;
718 }
719 if (nativeLibraryPath.empty()) {
720 return false;
721 }
722
723 tmpSoPath = (tmpSoPath.back() == Constants::PATH_SEPARATOR[0]) ? (tmpSoPath + moduleName) :
724 (tmpSoPath + Constants::PATH_SEPARATOR + moduleName);
725 ExtractParam extractParam;
726 extractParam.extractFileType = ExtractFileType::SO;
727 extractParam.srcPath = iter->hapPath;
728 extractParam.targetPath = tmpSoPath;
729 extractParam.cpuAbi = cpuAbi;
730 if (InstalldClient::GetInstance()->ExtractFiles(extractParam) != ERR_OK) {
731 APP_LOGW("bundleName: %{public}s moduleName: %{public}s extract so failed, ",
732 bundleInfo.name.c_str(), moduleName.c_str());
733 return false;
734 }
735 return true;
736 }
737
ProcessApplyDiffPatch(const AppQuickFix & appQuickFix,const HqfInfo & hqf,const std::string & oldSoPath,const std::string & patchPath)738 ErrCode QuickFixDeployer::ProcessApplyDiffPatch(const AppQuickFix &appQuickFix, const HqfInfo &hqf,
739 const std::string &oldSoPath, const std::string &patchPath)
740 {
741 std::string libraryPath;
742 std::string cpuAbi;
743 bool isLibIsolated = IsLibIsolated(appQuickFix.bundleName, hqf.moduleName);
744 if (!FetchPatchNativeSoAttrs(appQuickFix.deployingAppqfInfo, hqf, isLibIsolated, libraryPath, cpuAbi)) {
745 return ERR_OK;
746 }
747 // extract diff so, diff so path
748 std::string diffFilePath = Constants::HAP_COPY_PATH + Constants::PATH_SEPARATOR +
749 appQuickFix.bundleName + Constants::TMP_SUFFIX;
750 ScopeGuard guardRemoveDiffPath([diffFilePath] { InstalldClient::GetInstance()->RemoveDir(diffFilePath); });
751 // extract diff so to targetPath
752 auto ret = InstalldClient::GetInstance()->ExtractDiffFiles(hqf.hqfFilePath, diffFilePath, cpuAbi);
753 if (ret != ERR_OK) {
754 APP_LOGE("error: ExtractDiffFiles failed errcode :%{public}d", ret);
755 return ERR_BUNDLEMANAGER_QUICK_FIX_EXTRACT_DIFF_FILES_FAILED;
756 }
757 // apply diff patch
758 std::string newSoPath = patchPath + Constants::PATH_SEPARATOR + libraryPath;
759 ret = InstalldClient::GetInstance()->ApplyDiffPatch(oldSoPath, diffFilePath, newSoPath);
760 if (ret != ERR_OK) {
761 APP_LOGE("ApplyDiffPatch failed, bundleName:%{public}s, errcode: %{public}d",
762 appQuickFix.bundleName.c_str(), ret);
763 return ERR_BUNDLEMANAGER_QUICK_FIX_APPLY_DIFF_PATCH_FAILED;
764 }
765 return ERR_OK;
766 }
767 } // AppExecFwk
768 } // OHOS