1 /*
2  * Copyright (c) 2023 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 "module_update_main.h"
17 
18 #include <fcntl.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <thread>
22 #include <unistd.h>
23 
24 #include "directory_ex.h"
25 #include "module_utils.h"
26 #include "hisysevent_manager.h"
27 #include "json_node.h"
28 #include "log/log.h"
29 #include "module_update_service.h"
30 #include "parameter.h"
31 #include "system_ability_definition.h"
32 #include "module_constants.h"
33 #include "module_update_consumer.h"
34 #include "module_update_producer.h"
35 #include "module_error_code.h"
36 #include "module_file.h"
37 #include "module_update.h"
38 #include "package/package.h"
39 #include "scope_guard.h"
40 #include "utils.h"
41 #include "unique_fd.h"
42 
43 #ifdef WITH_SELINUX
44 #include <policycoreutils.h>
45 #endif // WITH_SELINUX
46 
47 namespace OHOS {
48 namespace SysInstaller {
49 using namespace Updater;
50 
51 namespace {
52 constexpr int32_t RETRY_TIMES_FOR_SAMGR = 10;
53 constexpr std::chrono::milliseconds MILLISECONDS_WAITING_SAMGR_ONE_TIME(100);
54 constexpr mode_t DIR_MODE = 0750;
55 
56 static volatile sig_atomic_t g_exit = 0;
57 
CreateModuleDirs(const std::string & hmpName)58 int32_t CreateModuleDirs(const std::string &hmpName)
59 {
60     if (!CreateDirIfNeeded(UPDATE_INSTALL_DIR, DIR_MODE)) {
61         LOG(ERROR) << "Failed to create install dir";
62         return ModuleErrorCode::ERR_INSTALL_FAIL;
63     }
64 #ifdef WITH_SELINUX
65     if (Restorecon(UPDATE_INSTALL_DIR) == -1) {
66         LOG(WARNING) << "restore " << UPDATE_INSTALL_DIR << " failed";
67     }
68 #endif // WITH_SELINUX
69     std::string hmpInstallDir = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
70     if (!CreateDirIfNeeded(hmpInstallDir, DIR_MODE)) {
71         LOG(ERROR) << "Failed to create hmp install dir " << hmpInstallDir;
72         return ModuleErrorCode::ERR_INSTALL_FAIL;
73     }
74     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
75 }
76 
GetFileAllName(const std::string & path)77 std::string GetFileAllName(const std::string &path)
78 {
79     auto pos = path.find_last_of('/');
80     if (pos == std::string::npos) {
81         pos = path.find_last_of('\\');
82         if (pos == std::string::npos) {
83             return "";
84         }
85     }
86     return path.substr(pos + 1);
87 }
88 
BackupFile(const std::string & file)89 bool BackupFile(const std::string &file)
90 {
91     std::string fileName = GetFileAllName(file);
92     std::string hmpName = GetHmpName(file);
93     if (fileName.empty() || hmpName.empty()) {
94         return true;
95     }
96     std::string destPath = std::string(UPDATE_BACKUP_DIR) + "/" + hmpName;
97     if (!CreateDirIfNeeded(destPath, DIR_MODE)) {
98         LOG(ERROR) << "Failed to create hmp dir " << destPath;
99         return false;
100     }
101     std::string destFile = destPath + "/" + fileName;
102     int ret = link(file.c_str(), destFile.c_str());
103     if (ret != 0) {
104         LOG(ERROR) << "Failed to link file " << file << " to dest " << destFile;
105         return false;
106     }
107     return true;
108 }
109 }
110 
ModuleUpdateMain()111 ModuleUpdateMain::ModuleUpdateMain()
112 {
113 }
114 
115 ModuleUpdateMain::~ModuleUpdateMain() = default;
116 
DoHotInstall(ModuleUpdateStatus & status)117 bool ModuleUpdateMain::DoHotInstall(ModuleUpdateStatus &status)
118 {
119     if (!status.isHotInstall) {
120         if (status.type == COLD_APP_TYPE || status.type == COLD_MIX_TYPE) {
121             SetParameter(BMS_START_INSTALL, BMS_UPDATE);
122         }
123         return true;
124     }
125     LOG(INFO) << "DoHotInstall, hmpName=" << status.hmpName << " ;type=" << status.type;
126     if (status.type == HOT_APP_TYPE) {
127         return HotAppInstall(status);
128     } else if (status.type == HOT_SA_TYPE) {
129         HotSaInstall(status);
130     }
131     return true;
132 }
133 
HotSaInstall(ModuleUpdateStatus & status)134 void ModuleUpdateMain::HotSaInstall(ModuleUpdateStatus &status)
135 {
136     if (!ModuleUpdate::GetInstance().DoModuleUpdate(status)) {
137         LOG(ERROR) << "HotSaInstall fail, hmpName=" << status.hmpName;
138         return;
139     }
140     RemoveSpecifiedDir(std::string(UPDATE_INSTALL_DIR) + "/" + status.hmpName);
141 }
142 
HotAppInstall(ModuleUpdateStatus & status)143 bool ModuleUpdateMain::HotAppInstall(ModuleUpdateStatus &status)
144 {
145     ON_SCOPE_EXIT(rmdir) {
146         RemoveSpecifiedDir(std::string(UPDATE_INSTALL_DIR) + "/" + status.hmpName);
147     };
148     if (!ModuleUpdate::GetInstance().DoModuleUpdate(status)) {
149         LOG(ERROR) << "HotAppInstall fail, hmpName=" << status.hmpName;
150         HotAppInstallWhenUpdateFail(status);
151         return false;
152     }
153     std::string hmpPath = std::string(MODULE_ROOT_DIR) + "/" + status.hmpName;
154     if (InstallHmpBundle(hmpPath, false)) {
155         LOG(INFO) << "HotAppInstall, install app succ; hmpName=" << status.hmpName;
156         return true;
157     }
158     // remove mountPoint and redo ModuleUpdate; even remove fail, still revert.
159     (void)ModuleUpdate::GetInstance().RemoveMountPoint(status.hmpName);
160     Revert(status.hmpName, false);
161     FirstRevertInstallHotApp(status);
162     return false;
163 }
164 
HotAppInstallWhenUpdateFail(ModuleUpdateStatus & status)165 void ModuleUpdateMain::HotAppInstallWhenUpdateFail(ModuleUpdateStatus &status)
166 {
167     std::string hmpPath = std::string(MODULE_ROOT_DIR) + "/" + status.hmpName;
168     // if /module_update/hmp exist, do not revert
169     if (CheckPathExists(hmpPath)) {
170         LOG(ERROR) << "Current module img is the same with last, don't revert; hmpName:" << status.hmpName;
171         return;
172     }
173     FirstRevertInstallHotApp(status);
174 }
175 
FirstRevertInstallHotApp(ModuleUpdateStatus & status)176 void ModuleUpdateMain::FirstRevertInstallHotApp(ModuleUpdateStatus &status)
177 {
178     LOG(WARNING) << "First revert hot app, hmpName=" << status.hmpName;
179     std::string activeHmpPath = std::string(UPDATE_ACTIVE_DIR) + "/" + status.hmpName;
180     std::string hmpPath = std::string(MODULE_ROOT_DIR) + "/" + status.hmpName;
181     if (!ModuleUpdate::GetInstance().DoModuleUpdate(status)) {
182         LOG(ERROR) << "First revert fail, hmpName=" << status.hmpName;
183         SecondRevertInstallHotApp(status);
184         return;
185     }
186     if (InstallHmpBundle(hmpPath, true)) {
187         LOG(INFO) << "After first revert, install app succ; hmpName=" << status.hmpName;
188         return;
189     }
190     SecondRevertInstallHotApp(status);
191 }
192 
SecondRevertInstallHotApp(ModuleUpdateStatus & status)193 void ModuleUpdateMain::SecondRevertInstallHotApp(ModuleUpdateStatus &status)
194 {
195     LOG(WARNING) << "Second revert hot app, hmpName=" << status.hmpName;
196     std::string activeHmpPath = std::string(UPDATE_ACTIVE_DIR) + "/" + status.hmpName;
197     std::string hmpPath = std::string(MODULE_ROOT_DIR) + "/" + status.hmpName;
198     if (!CheckPathExists(activeHmpPath) && CheckPathExists(hmpPath)) {
199         LOG(WARNING) << "current IMG is preinstall, force to install; hmpName:" << status.hmpName;
200         (void)InstallHmpBundle(hmpPath, true);
201         return;
202     }
203     (void)ModuleUpdate::GetInstance().RemoveMountPoint(status.hmpName);
204     Revert(status.hmpName, false);
205     (void)ModuleUpdate::GetInstance().DoModuleUpdate(status);
206     if (!CheckPathExists(hmpPath)) {
207         LOG(ERROR) << "HotApp, Second Revert hmpName: " << status.hmpName <<  " fail.";
208         return;
209     }
210     (void)InstallHmpBundle(hmpPath, true);
211 }
212 
CheckHmpName(const std::string & hmpName)213 int32_t ModuleUpdateMain::CheckHmpName(const std::string &hmpName)
214 {
215     if (hmpName.empty()) {
216         LOG(ERROR) << "Failed to get hmpName=" << hmpName;
217         return ModuleErrorCode::ERR_INVALID_PATH;
218     }
219     if (hmpSet_.find(hmpName) == hmpSet_.end()) {
220         LOG(ERROR) << "Failed to install hmp without preInstall";
221         return ModuleErrorCode::ERR_INSTALL_FAIL;
222     }
223     int32_t ret = CreateModuleDirs(hmpName);
224     if (ret != ModuleErrorCode::MODULE_UPDATE_SUCCESS) {
225         RemoveSpecifiedDir(std::string(UPDATE_INSTALL_DIR) + "/" + hmpName);
226         return ret;
227     }
228     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
229 }
230 
ReallyInstallModulePackage(const std::string & pkgPath,const sptr<ISysInstallerCallback> & updateCallback)231 int32_t ModuleUpdateMain::ReallyInstallModulePackage(const std::string &pkgPath,
232     const sptr<ISysInstallerCallback> &updateCallback)
233 {
234     std::string hmpName = GetFileName(pkgPath);
235     int32_t ret = CheckHmpName(hmpName);
236     if (ret != ModuleErrorCode::MODULE_UPDATE_SUCCESS) {
237         return ret;
238     }
239     std::string hmpDir = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
240     ON_SCOPE_EXIT(rmdir) {
241         RemoveSpecifiedDir(hmpDir);
242     };
243     std::string outPath = hmpDir + "/";
244     ret = ExtraPackageDir(pkgPath.c_str(), nullptr, nullptr, outPath.c_str());
245     if (ret != 0) {
246         LOG(ERROR) << "Failed to unpack hmp package " << pkgPath;
247         return ModuleErrorCode::ERR_INSTALL_FAIL;
248     }
249     std::vector<std::string> files;
250     GetDirFiles(hmpDir, files);
251     // for check hot hmp
252     ModuleUpdateStatus status;
253     status.hmpName = hmpName;
254     int index = 1;
255     for (auto &file : files) {
256         ret = InstallModuleFile(hmpName, file, status);
257         if (ret != ModuleErrorCode::MODULE_UPDATE_SUCCESS) {
258             return ret;
259         }
260         if (updateCallback != nullptr) {
261             int percent = static_cast<float>(index) / files.size() * 95;  // 95 : 95% percent
262             updateCallback->OnUpgradeProgress(UPDATE_STATE_ONGOING, percent, "");
263         }
264         index++;
265     }
266     if (!BackupActiveModules(hmpName)) {
267         LOG(ERROR) << "Failed to backup active hmp: " << hmpName;
268         return ModuleErrorCode::ERR_INSTALL_FAIL;
269     }
270     CANCEL_SCOPE_EXIT_GUARD(rmdir);
271 
272     // create avtive hmp dir finally, avoid to be backup.
273     std::string hmpActiveDir = std::string(UPDATE_ACTIVE_DIR) + "/" + hmpName;
274     if (!CreateDirIfNeeded(hmpActiveDir, DIR_MODE)) {
275         LOG(ERROR) << "Failed to create hmp active dir " << hmpActiveDir;
276         return ModuleErrorCode::ERR_INSTALL_FAIL;
277     }
278     if (!DoHotInstall(status)) {
279         sync();
280         return ModuleErrorCode::ERR_INSTALL_FAIL;
281     }
282     sync();
283     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
284 }
285 
ValidateVersion(ModuleFile & installFile,const std::string & hmpName) const286 int32_t ModuleUpdateMain::ValidateVersion(ModuleFile &installFile, const std::string &hmpName) const
287 {
288     std::string preInstalledPath = std::string(MODULE_PREINSTALL_DIR) + "/" + hmpName + "/" + HMP_INFO_NAME;
289     std::unique_ptr<ModuleFile> preInstalledFile = ModuleFile::Open(preInstalledPath);
290     if (preInstalledFile == nullptr) {
291         LOG(ERROR) << "Invalid preinstalled file " << preInstalledPath;
292         return ModuleErrorCode::ERR_INSTALL_FAIL;
293     }
294     if (!ModuleFile::CompareVersion(installFile, *preInstalledFile)) {
295         LOG(ERROR) << "Installed version is lower than preInstall.";
296         return ModuleErrorCode::ERR_LOWER_VERSION;
297     }
298     if (!installFile.VerifyModuleVerity()) {
299         LOG(ERROR) << "Failed to verify install img: " << hmpName;
300         return ModuleErrorCode::ERR_VERIFY_SIGN_FAIL;
301     }
302 
303     std::string activePath = std::string(UPDATE_ACTIVE_DIR) + "/" + hmpName + "/" + HMP_INFO_NAME;
304     if (!Utils::IsFileExist(activePath)) {
305         return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
306     }
307     std::unique_ptr<ModuleFile> activeFile = ModuleFile::Open(activePath);
308     if (activeFile == nullptr) {
309         LOG(WARNING) << "Invalid active file " << activePath;
310         return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
311     }
312     if (!ModuleFile::CompareVersion(installFile, *activeFile)) {
313         LOG(ERROR) << "Installed version is lower than active.";
314         return ModuleErrorCode::ERR_LOWER_VERSION;
315     }
316     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
317 }
318 
InstallModuleFile(const std::string & hmpName,const std::string & file,ModuleUpdateStatus & status) const319 int32_t ModuleUpdateMain::InstallModuleFile(const std::string &hmpName, const std::string &file,
320     ModuleUpdateStatus &status) const
321 {
322     if (!CheckFileSuffix(file, MODULE_PACKAGE_SUFFIX)) {
323         return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
324     }
325     std::string fileName = GetFileName(file);
326     if (fileName.empty()) {
327         return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
328     }
329     // verify first, then open module file.
330     if (VerifyModulePackageSign(file) != 0) {
331         LOG(ERROR) << "Verify sign failed " << file;
332         return ModuleErrorCode::ERR_VERIFY_SIGN_FAIL;
333     }
334 
335     std::unique_ptr<ModuleFile> moduleFile = ModuleFile::Open(file);
336     if (moduleFile == nullptr) {
337         LOG(ERROR) << "Wrong module file " << file << " in hmp package " << hmpName;
338         return ModuleErrorCode::ERR_INSTALL_FAIL;
339     }
340     if (!moduleFile->GetImageStat().has_value()) {
341         LOG(ERROR) << "Could not install empty module package " << file;
342         return ModuleErrorCode::ERR_INSTALL_FAIL;
343     }
344     if (ValidateVersion(*moduleFile, hmpName) != ModuleErrorCode::MODULE_UPDATE_SUCCESS) {
345         return ModuleErrorCode::ERR_INSTALL_FAIL;
346     }
347     status.type = moduleFile->GetHmpPackageType();
348     status.isHotInstall = IsHotHmpPackage(static_cast<int32_t>(status.type));
349     moduleFile->ClearVerifiedData();
350     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
351 }
352 
UninstallModulePackage(const std::string & hmpName)353 int32_t ModuleUpdateMain::UninstallModulePackage(const std::string &hmpName)
354 {
355     LOG(INFO) << "UninstallModulePackage " << hmpName;
356     int ret = ModuleErrorCode::MODULE_UPDATE_SUCCESS;
357     if (hmpName.empty() || hmpSet_.find(hmpName) == hmpSet_.end()) {
358         return ModuleErrorCode::ERR_INVALID_PATH;
359     }
360     std::vector<std::string> uninstallDir {UPDATE_INSTALL_DIR, UPDATE_ACTIVE_DIR, UPDATE_BACKUP_DIR};
361     std::string hmpDir = "/" + hmpName;
362     bool hmpIsValid = false;
363     for (const auto &iter : uninstallDir) {
364         std::string dir = iter + hmpDir;
365         if (!CheckPathExists(dir)) {
366             continue;
367         }
368         hmpIsValid = true;
369         if (!ForceRemoveDirectory(dir)) {
370             LOG(ERROR) << "Failed to remove " << dir;
371             ret = ModuleErrorCode::ERR_UNINSTALL_FAIL;
372         }
373     }
374     if (!hmpIsValid) {
375         ret = ModuleErrorCode::ERR_INVALID_PATH;
376     }
377     return ret;
378 }
379 
GetModulePackageInfo(const std::string & hmpName,std::list<ModulePackageInfo> & modulePackageInfos)380 int32_t ModuleUpdateMain::GetModulePackageInfo(const std::string &hmpName,
381     std::list<ModulePackageInfo> &modulePackageInfos)
382 {
383     LOG(INFO) << "GetModulePackageInfo " << hmpName;
384     if (hmpName.empty()) {
385         for (auto &hmp : hmpSet_) {
386             CollectModulePackageInfo(hmp, modulePackageInfos);
387         }
388     } else if (find(hmpSet_.begin(), hmpSet_.end(), hmpName) != hmpSet_.end()) {
389         CollectModulePackageInfo(hmpName, modulePackageInfos);
390     } else {
391         LOG(ERROR) << hmpName << " not exist in hmpSet";
392         return ModuleErrorCode::MODULE_UPDATE_FAIL;
393     }
394     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
395 }
CollectModulePackageInfo(const std::string & hmpName,std::list<ModulePackageInfo> & modulePackageInfos) const396 void ModuleUpdateMain::CollectModulePackageInfo(const std::string &hmpName,
397     std::list<ModulePackageInfo> &modulePackageInfos) const
398 {
399     if (hmpName.empty()) {
400         return;
401     }
402     std::string installHmpPath = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
403     std::string activeHmpPath = std::string(UPDATE_ACTIVE_DIR) + "/" + hmpName;
404     if (!CheckPathExists(installHmpPath) && !CheckPathExists(activeHmpPath)) {
405         return;
406     }
407     std::vector<std::string> files;
408     GetDirFiles(installHmpPath, files);
409     GetDirFiles(activeHmpPath, files);
410     for (auto &file : files) {
411         if (!CheckFileSuffix(file, MODULE_PACKAGE_SUFFIX)) {
412             continue;
413         }
414         std::unique_ptr<ModuleFile> moduleFile = ModuleFile::Open(file);
415         if (moduleFile == nullptr) {
416             return;
417         }
418         modulePackageInfos.emplace_back(std::move(moduleFile->GetVersionInfo()));
419     }
420 }
421 
ExitModuleUpdate()422 void ModuleUpdateMain::ExitModuleUpdate()
423 {
424     LOG(INFO) << "ExitModuleUpdate";
425     Stop();
426 }
427 
GetHmpVersion(const std::string & hmpPath,HmpVersionInfo & versionInfo)428 bool ModuleUpdateMain::GetHmpVersion(const std::string &hmpPath, HmpVersionInfo &versionInfo)
429 {
430     LOG(INFO) << "GetHmpVersion " << hmpPath;
431     std::string packInfoPath = hmpPath + "/" + HMP_INFO_NAME;
432     if (!Utils::IsFileExist(packInfoPath)) {
433         LOG(ERROR) << "pack.info is not exist: " << packInfoPath;
434         return false;
435     }
436     if (!StartsWith(packInfoPath, MODULE_PREINSTALL_DIR) &&
437         VerifyModulePackageSign(packInfoPath) != 0) {
438         LOG(ERROR) << "Verify sign failed " << packInfoPath;
439         return false;
440     }
441     std::string packInfo = GetContentFromZip(packInfoPath, PACK_INFO_NAME);
442     JsonNode root(packInfo);
443     const JsonNode &package = root["package"];
444     std::optional<std::string> name = package["name"].As<std::string>();
445     if (!name.has_value()) {
446         LOG(ERROR) << "count get name val";
447         return false;
448     }
449 
450     std::optional<std::string> version = package["version"].As<std::string>();
451     if (!version.has_value()) {
452         LOG(ERROR) << "count get version val";
453         return false;
454     }
455 
456     const JsonNode &laneInfoNode = package["laneInfo"];
457     std::optional<std::string> compatibleVersion = laneInfoNode["compatibleVersion"].As<std::string>();
458     if (!compatibleVersion.has_value()) {
459         LOG(ERROR) << "count get compatibleVersion val";
460         return false;
461     }
462 
463     std::optional<std::string> laneCode = laneInfoNode["laneCode"].As<std::string>();
464     if (!laneCode.has_value()) {
465         LOG(ERROR) << "count get laneCode val";
466         return false;
467     }
468 
469     versionInfo.name = name.value();
470     versionInfo.version = version.value();
471     versionInfo.compatibleVersion = compatibleVersion.value();
472     versionInfo.laneCode = laneCode.value();
473     return true;
474 }
475 
ParseHmpVersionInfo(std::vector<HmpVersionInfo> & versionInfos,const HmpVersionInfo & preInfo,const HmpVersionInfo & actInfo)476 void ModuleUpdateMain::ParseHmpVersionInfo(std::vector<HmpVersionInfo> &versionInfos, const HmpVersionInfo &preInfo,
477     const HmpVersionInfo &actInfo)
478 {
479     if (preInfo.version.size() == 0 && actInfo.version.size() == 0) {
480         LOG(WARNING) << "version is empty";
481         return;
482     }
483 
484     if (actInfo.version.size() == 0) {
485         LOG(INFO) << "add preinstaller info";
486         versionInfos.emplace_back(preInfo);
487         return;
488     }
489     std::vector<std::string> preVersion {};
490     std::vector<std::string> actVersion {};
491     // version: xxx-d01 M.S.F.B
492     if (!ParseVersion(preInfo.version, " ", preVersion)) {
493         LOG(ERROR) << "Parse preVersion failed.";
494         return;
495     }
496 
497     if (!ParseVersion(actInfo.version, " ", actVersion)) {
498         LOG(WARNING) << "Parse actVersion failed.";
499         versionInfos.emplace_back(preInfo);
500         return;
501     }
502 
503     if (CompareHmpVersion(preVersion, actVersion)) {
504         LOG(INFO) << "add active info";
505         versionInfos.emplace_back(actInfo);
506     } else {
507         LOG(INFO) << "add preinstaller info";
508         versionInfos.emplace_back(preInfo);
509     }
510 }
511 
GetHmpVersionInfo()512 std::vector<HmpVersionInfo> ModuleUpdateMain::GetHmpVersionInfo()
513 {
514     LOG(INFO) << "GetHmpVersionInfo";
515     std::vector<HmpVersionInfo> versionInfos {};
516     ScanPreInstalledHmp();
517     for (auto &hmp : hmpSet_) {
518         std::string preInstallHmpPath = std::string(MODULE_PREINSTALL_DIR) + "/" + hmp;
519         std::string activeHmpPath = std::string(UPDATE_ACTIVE_DIR) + "/" + hmp;
520         LOG(INFO) << "preInstallHmpPath:" << preInstallHmpPath << " activeHmpPath:" << activeHmpPath;
521         HmpVersionInfo actinfo {};
522         HmpVersionInfo preinfo {};
523         (void)GetHmpVersion(preInstallHmpPath, preinfo);
524         (void)GetHmpVersion(activeHmpPath, actinfo);
525         ParseHmpVersionInfo(versionInfos, preinfo, actinfo);
526     }
527     return versionInfos;
528 }
529 
SaveInstallerResult(const std::string & hmpPath,int result,const std::string & resultInfo,const Timer & timer)530 void ModuleUpdateMain::SaveInstallerResult(const std::string &hmpPath, int result,
531     const std::string &resultInfo, const Timer &timer)
532 {
533     LOG(INFO) << "hmpPath:" << hmpPath << " result:" << result << " resultInfo:" << resultInfo;
534     UniqueFd fd(open(MODULE_RESULT_PATH, O_APPEND | O_RDWR | O_CREAT | O_CLOEXEC));
535     if (fd.Get() == -1) {
536         LOG(ERROR) << "Failed to open file";
537         return;
538     }
539     constexpr mode_t mode = 0755; // 0755 : rwx-r-x-r-x
540     if (chmod(MODULE_RESULT_PATH, mode) != 0) {
541         LOG(ERROR) << "Could not chmod " << MODULE_RESULT_PATH;
542     }
543     std::string writeInfo = hmpPath + ";" + std::to_string(result) + ";" +
544         resultInfo + "|" + std::to_string(timer.duration().count()) + "\n";
545     if (CheckAndUpdateRevertResult(hmpPath, writeInfo, "revert")) {
546         return;
547     }
548     if (write(fd, writeInfo.data(), writeInfo.length()) <= 0) {
549         LOG(WARNING) << "write result file failed, err:" << errno;
550     }
551     fsync(fd.Get());
552 }
553 
BackupActiveModules(const std::string & hmpName) const554 bool ModuleUpdateMain::BackupActiveModules(const std::string &hmpName) const
555 {
556     std::string activePath = std::string(UPDATE_ACTIVE_DIR) + "/" + hmpName;
557     if (!CheckPathExists(activePath)) {
558         LOG(INFO) << "Nothing to backup, path: " << activePath;
559         return true;
560     }
561     std::string backupPath = std::string(UPDATE_BACKUP_DIR) + "/" + hmpName;
562     if (CheckPathExists(backupPath)) {
563         if (!ForceRemoveDirectory(backupPath)) {
564             LOG(ERROR) << "Failed to remove backup dir:" << backupPath;
565             return false;
566         }
567     }
568     if (!CreateDirIfNeeded(backupPath, DIR_MODE)) {
569         LOG(ERROR) << "Failed to create backup dir:" << backupPath;
570         return false;
571     }
572 
573     std::vector<std::string> activeFiles;
574     GetDirFiles(activePath, activeFiles);
575     ON_SCOPE_EXIT(rmdir) {
576         if (!ForceRemoveDirectory(backupPath)) {
577             LOG(WARNING) << "Failed to remove backup dir when backup failed";
578         }
579     };
580     for (const auto &file : activeFiles) {
581         if (!BackupFile(file)) {
582             return false;
583         }
584     }
585 
586     CANCEL_SCOPE_EXIT_GUARD(rmdir);
587     return true;
588 }
589 
ScanPreInstalledHmp()590 void ModuleUpdateMain::ScanPreInstalledHmp()
591 {
592     std::vector<std::string> files;
593     GetDirFiles(MODULE_PREINSTALL_DIR, files);
594     for (auto &file : files) {
595         if (!CheckFileSuffix(file, MODULE_PACKAGE_SUFFIX)) {
596             continue;
597         }
598         std::unique_ptr<ModuleFile> moduleFile = ModuleFile::Open(file);
599         if (moduleFile == nullptr) {
600             continue;
601         }
602         std::string hmpName = GetHmpName(file);
603         if (hmpName.empty()) {
604             continue;
605         }
606         std::unique_lock<std::mutex> locker(mlock_);
607         hmpSet_.emplace(hmpName);
608         for (const auto &saInfo : moduleFile->GetVersionInfo().saInfoList) {
609             saIdHmpMap_.emplace(saInfo.saId, hmpName);
610         }
611     }
612 }
613 
GetSystemAbilityManager()614 sptr<ISystemAbilityManager> &ModuleUpdateMain::GetSystemAbilityManager()
615 {
616     if (samgr_ != nullptr) {
617         return samgr_;
618     }
619     int32_t times = RETRY_TIMES_FOR_SAMGR;
620     constexpr int32_t duration = std::chrono::microseconds(MILLISECONDS_WAITING_SAMGR_ONE_TIME).count();
621     while (times > 0) {
622         times--;
623         samgr_ = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
624         if (samgr_ == nullptr) {
625             LOG(INFO) << "waiting for samgr";
626             usleep(duration);
627         } else {
628             break;
629         }
630     }
631     return samgr_;
632 }
633 
Start()634 void ModuleUpdateMain::Start()
635 {
636     LOG(INFO) << "ModuleUpdateMain Start";
637     ModuleUpdateQueue queue;
638     ModuleUpdateProducer producer(queue, saIdHmpMap_, hmpSet_, g_exit);
639     ModuleUpdateConsumer consumer(queue, saIdHmpMap_, g_exit);
640     std::thread produceThread([&producer] {
641         producer.Run();
642         });
643     std::thread consumeThread([&consumer] {
644         consumer.Run();
645         });
646     consumeThread.join();
647     produceThread.join();
648     LOG(INFO) << "module update main exit";
649 }
650 
Stop()651 void ModuleUpdateMain::Stop()
652 {
653     LOG(INFO) << "ModuleUpdateMain Stop";
654     g_exit = 1;
655 }
656 } // namespace SysInstaller
657 } // namespace OHOS