• 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_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