• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_service.h"
17 
18 #include "directory_ex.h"
19 #include "log/log.h"
20 #include "module_constants.h"
21 #include "module_error_code.h"
22 #include "module_file.h"
23 #include "module_utils.h"
24 #include "package/package.h"
25 #include "scope_guard.h"
26 #include "system_ability_definition.h"
27 #include "utils.h"
28 
29 namespace OHOS {
30 namespace SysInstaller {
31 using namespace Updater;
32 
33 namespace {
34 constexpr mode_t DIR_MODE = 0750;
35 constexpr mode_t ALL_PERMISSIONS = 0777;
36 
CreateModuleDirs(const std::string & hmpName)37 int32_t CreateModuleDirs(const std::string &hmpName)
38 {
39     if (!CreateDirIfNeeded(UPDATE_INSTALL_DIR, DIR_MODE)) {
40         LOG(ERROR) << "Failed to create install dir";
41         return ModuleErrorCode::ERR_INSTALL_FAIL;
42     }
43     std::string hmpInstallDir = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
44     if (!CreateDirIfNeeded(hmpInstallDir, DIR_MODE)) {
45         LOG(ERROR) << "Failed to create hmp install dir " << hmpInstallDir;
46         return ModuleErrorCode::ERR_INSTALL_FAIL;
47     }
48     std::string hmpActiveDir = std::string(UPDATE_ACTIVE_DIR) + "/" + hmpName;
49     if (!CreateDirIfNeeded(hmpActiveDir, DIR_MODE)) {
50         LOG(ERROR) << "Failed to create hmp active dir " << hmpActiveDir;
51         return ModuleErrorCode::ERR_INSTALL_FAIL;
52     }
53     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
54 }
55 
ClearModuleDirs(const std::string & hmpName)56 bool ClearModuleDirs(const std::string &hmpName)
57 {
58     std::string hmpInstallDir = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
59     std::string hmpActiveDir = std::string(UPDATE_ACTIVE_DIR) + "/" + hmpName;
60     return ForceRemoveDirectory(hmpInstallDir) && ForceRemoveDirectory(hmpActiveDir);
61 }
62 
BackupFile(const std::string & file)63 bool BackupFile(const std::string &file)
64 {
65     if (!CheckFileSuffix(file, MODULE_PACKAGE_SUFFIX)) {
66         return true;
67     }
68     std::string fileName = GetFileName(file);
69     std::string hmpName = GetHmpName(file);
70     if (fileName.empty() || hmpName.empty()) {
71         return true;
72     }
73     std::unique_ptr<ModuleFile> moduleFile = ModuleFile::Open(file);
74     if (moduleFile == nullptr) {
75         LOG(ERROR) << "Wrong module file " << file << " in active dir";
76         return false;
77     }
78     std::string destPath = std::string(UPDATE_BACKUP_DIR) + "/" + hmpName;
79     if (!CreateDirIfNeeded(destPath, DIR_MODE)) {
80         LOG(ERROR) << "Failed to create hmp dir " << destPath;
81         return false;
82     }
83     std::string destFile = destPath + "/" + fileName + MODULE_PACKAGE_SUFFIX;
84     int ret = link(file.c_str(), destFile.c_str());
85     if (ret != 0) {
86         LOG(ERROR) << "Failed to link file " << file << " to dest " << destFile;
87         return false;
88     }
89     return true;
90 }
91 }
92 
ModuleUpdateService()93 ModuleUpdateService::ModuleUpdateService() : SystemAbility(MODULE_UPDATE_SERVICE_ID, true)
94 {
95     LOG(INFO) << "ModuleUpdateService begin";
96 }
97 
~ModuleUpdateService()98 ModuleUpdateService::~ModuleUpdateService()
99 {
100     LOG(INFO) << "ModuleUpdateService end";
101 }
102 
InstallModulePackage(const std::string & pkgPath)103 int32_t ModuleUpdateService::InstallModulePackage(const std::string &pkgPath)
104 {
105     LOG(INFO) << "InstallModulePackage " << pkgPath;
106     std::string realPath;
107     if (!CheckFileSuffix(pkgPath, HMP_PACKAGE_SUFFIX) || !PathToRealPath(pkgPath, realPath)) {
108         LOG(ERROR) << "Invalid package path " << pkgPath;
109         return ModuleErrorCode::ERR_INVALID_PATH;
110     }
111     std::string hmpName = GetFileName(realPath);
112     if (hmpName.empty()) {
113         LOG(ERROR) << "Failed to get hmp name " << realPath;
114         return ModuleErrorCode::ERR_INVALID_PATH;
115     }
116     if (hmpSet_.find(hmpName) == hmpSet_.end()) {
117         LOG(ERROR) << "Failed to install hmp without preInstall";
118         return ModuleErrorCode::ERR_INSTALL_FAIL;
119     }
120     int32_t ret = CreateModuleDirs(hmpName);
121     if (ret != ModuleErrorCode::MODULE_UPDATE_SUCCESS) {
122         ClearModuleDirs(hmpName);
123         return ret;
124     }
125     ON_SCOPE_EXIT(rmdir) {
126         if (!ClearModuleDirs(hmpName)) {
127             LOG(WARNING) << "Failed to remove " << hmpName;
128         }
129     };
130     std::string hmpDir = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
131     std::string outPath = hmpDir + "/";
132     ret = ExtraPackageDir(realPath.c_str(), nullptr, nullptr, outPath.c_str());
133     if (ret != 0) {
134         LOG(ERROR) << "Failed to unpack hmp package " << realPath;
135         return ModuleErrorCode::ERR_INSTALL_FAIL;
136     }
137     std::vector<std::string> files;
138     GetDirFiles(hmpDir, files);
139     for (auto &file : files) {
140         ret = InstallModuleFile(hmpName, file);
141         if (ret != ModuleErrorCode::MODULE_UPDATE_SUCCESS) {
142             return ret;
143         }
144     }
145     if (!BackupActiveModules()) {
146         LOG(ERROR) << "Failed to backup active modules";
147         return ModuleErrorCode::ERR_INSTALL_FAIL;
148     }
149     CANCEL_SCOPE_EXIT_GUARD(rmdir);
150     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
151 }
152 
InstallModuleFile(const std::string & hmpName,const std::string & file) const153 int32_t ModuleUpdateService::InstallModuleFile(const std::string &hmpName, const std::string &file) const
154 {
155     if (!CheckFileSuffix(file, MODULE_PACKAGE_SUFFIX)) {
156         return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
157     }
158     std::string fileName = GetFileName(file);
159     if (fileName.empty()) {
160         return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
161     }
162     std::unique_ptr<ModuleFile> moduleFile = ModuleFile::Open(file);
163     if (moduleFile == nullptr) {
164         LOG(ERROR) << "Wrong module file " << file << " in hmp package " << hmpName;
165         return ModuleErrorCode::ERR_INSTALL_FAIL;
166     }
167     if (!moduleFile->GetImageStat().has_value()) {
168         LOG(ERROR) << "Could not install empty module package " << file;
169         return ModuleErrorCode::ERR_INSTALL_FAIL;
170     }
171     if (saIdHmpMap_.find(moduleFile->GetSaId()) == saIdHmpMap_.end()) {
172         LOG(ERROR) << "Could not update module file " << file << " without preInstalled";
173         return ModuleErrorCode::ERR_INSTALL_FAIL;
174     }
175     std::string preInstalledHmp = saIdHmpMap_.at(moduleFile->GetSaId());
176     if (preInstalledHmp != hmpName) {
177         LOG(ERROR) << "Module file " << file << " should be in hmp " << preInstalledHmp;
178         return ModuleErrorCode::ERR_INSTALL_FAIL;
179     }
180     if (!ModuleFile::VerifyModulePackageSign(file)) {
181         LOG(ERROR) << "Verify sign failed " << file;
182         return ModuleErrorCode::ERR_VERIFY_SIGN_FAIL;
183     }
184 
185     std::string preInstalledPath = std::string(MODULE_PREINSTALL_DIR) + "/" + hmpName + "/" + fileName
186         + MODULE_PACKAGE_SUFFIX;
187     std::unique_ptr<ModuleFile> preInstalledFile = ModuleFile::Open(preInstalledPath);
188     if (preInstalledFile == nullptr) {
189         LOG(ERROR) << "Invalid preinstalled file " << preInstalledPath;
190         return ModuleErrorCode::ERR_INSTALL_FAIL;
191     }
192     if (!ModuleFile::CompareVersion(*moduleFile, *preInstalledFile)) {
193         LOG(ERROR) << "Installed lower version of " << file;
194         return ModuleErrorCode::ERR_LOWER_VERSION;
195     }
196     if (!moduleFile->VerifyModuleVerity(preInstalledFile->GetPublicKey())) {
197         LOG(ERROR) << "Failed to verify module verity " << file;
198         return ModuleErrorCode::ERR_VERIFY_SIGN_FAIL;
199     }
200     moduleFile->ClearVerifiedData();
201     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
202 }
203 
UninstallModulePackage(const std::string & hmpName)204 int32_t ModuleUpdateService::UninstallModulePackage(const std::string &hmpName)
205 {
206     LOG(INFO) << "UninstallModulePackage " << hmpName;
207     int ret = ModuleErrorCode::MODULE_UPDATE_SUCCESS;
208     if (hmpName.empty() || hmpSet_.find(hmpName) == hmpSet_.end()) {
209         return ModuleErrorCode::ERR_INVALID_PATH;
210     }
211     std::vector<std::string> uninstallDir {UPDATE_INSTALL_DIR, UPDATE_ACTIVE_DIR, UPDATE_BACKUP_DIR};
212     std::string hmpDir = "/" + hmpName;
213     bool hmpIsValid = false;
214     for (const auto &iter : uninstallDir) {
215         std::string dir = iter + hmpDir;
216         if (!CheckPathExists(dir)) {
217             continue;
218         }
219         hmpIsValid = true;
220         if (!ForceRemoveDirectory(dir)) {
221             LOG(ERROR) << "Failed to remove " << dir;
222             ret = ModuleErrorCode::ERR_UNINSTALL_FAIL;
223         }
224     }
225     if (!hmpIsValid) {
226         ret = ModuleErrorCode::ERR_INVALID_PATH;
227     }
228     return ret;
229 }
230 
GetModulePackageInfo(const std::string & hmpName,std::list<ModulePackageInfo> & modulePackageInfos)231 int32_t ModuleUpdateService::GetModulePackageInfo(const std::string &hmpName,
232     std::list<ModulePackageInfo> &modulePackageInfos)
233 {
234     LOG(INFO) << "GetModulePackageInfo " << hmpName;
235     if (hmpName.empty()) {
236         for (auto &hmp : hmpSet_) {
237             CollectModulePackageInfo(hmp, modulePackageInfos);
238         }
239     } else {
240         CollectModulePackageInfo(hmpName, modulePackageInfos);
241     }
242     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
243 }
244 
CollectModulePackageInfo(const std::string & hmpName,std::list<ModulePackageInfo> & modulePackageInfos) const245 void ModuleUpdateService::CollectModulePackageInfo(const std::string &hmpName,
246     std::list<ModulePackageInfo> &modulePackageInfos) const
247 {
248     if (hmpName.empty()) {
249         return;
250     }
251     std::string installHmpPath = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
252     std::string activeHmpPath = std::string(UPDATE_ACTIVE_DIR) + "/" + hmpName;
253     if (!CheckPathExists(installHmpPath) && !CheckPathExists(activeHmpPath)) {
254         return;
255     }
256     std::vector<std::string> files;
257     GetDirFiles(installHmpPath, files);
258     GetDirFiles(activeHmpPath, files);
259     ModulePackageInfo info;
260     info.hmpName = hmpName;
261     for (auto &file : files) {
262         if (!CheckFileSuffix(file, MODULE_PACKAGE_SUFFIX)) {
263             continue;
264         }
265         std::unique_ptr<ModuleFile> moduleFile = ModuleFile::Open(file);
266         if (moduleFile == nullptr) {
267             continue;
268         }
269         SaInfo saInfo;
270         saInfo.saName = moduleFile->GetSaName();
271         saInfo.saId = moduleFile->GetSaId();
272         saInfo.version = moduleFile->GetVersionInfo();
273         info.saInfoList.emplace_back(std::move(saInfo));
274     }
275     modulePackageInfos.emplace_back(std::move(info));
276 }
277 
ReportModuleUpdateStatus(const ModuleUpdateStatus & status)278 int32_t ModuleUpdateService::ReportModuleUpdateStatus(const ModuleUpdateStatus &status)
279 {
280     LOG(INFO) << "ReportModuleUpdateStatus process=" << status.process;
281     if (status.process.empty()) {
282         LOG(ERROR) << "empty process name";
283         return ModuleErrorCode::ERR_REPORT_STATUS_FAIL;
284     }
285     std::unordered_set<std::string> hmpSet;
286     for (const auto &iter : status.saStatusList) {
287         ProcessSaStatus(iter, hmpSet);
288     }
289     processHmpMap_.emplace(status.process, hmpSet);
290     return ModuleErrorCode::MODULE_UPDATE_SUCCESS;
291 }
292 
ExitModuleUpdate()293 int32_t ModuleUpdateService::ExitModuleUpdate()
294 {
295     LOG(INFO) << "ExitModuleUpdate";
296     exit(0);
297 }
298 
ProcessSaStatus(const SaStatus & status,std::unordered_set<std::string> & hmpSet)299 void ModuleUpdateService::ProcessSaStatus(const SaStatus &status, std::unordered_set<std::string> &hmpSet)
300 {
301     if (saIdHmpMap_.find(status.saId) == saIdHmpMap_.end()) {
302         return;
303     }
304     std::string hmpName = saIdHmpMap_.at(status.saId);
305     hmpSet.emplace(hmpName);
306     if (!status.isMountSuccess) {
307         OnHmpError(hmpName);
308     }
309 }
310 
OnStart()311 void ModuleUpdateService::OnStart()
312 {
313     LOG(INFO) << "OnStart";
314 }
315 
OnStop()316 void ModuleUpdateService::OnStop()
317 {
318     LOG(INFO) << "OnStop";
319 }
320 
OnProcessCrash(const std::string & processName)321 void ModuleUpdateService::OnProcessCrash(const std::string &processName)
322 {
323     if (processHmpMap_.find(processName) == processHmpMap_.end()) {
324         return;
325     }
326     std::unordered_set<std::string> &hmpSet = processHmpMap_.at(processName);
327     for (auto &hmp : hmpSet) {
328         OnHmpError(hmp);
329     }
330 }
331 
OnBootCompleted()332 void ModuleUpdateService::OnBootCompleted()
333 {
334     LOG(INFO) << "Deleting " << UPDATE_INSTALL_DIR;
335     if (!ForceRemoveDirectory(UPDATE_INSTALL_DIR)) {
336         LOG(ERROR) << "Failed to remove " << UPDATE_INSTALL_DIR << " err=" << errno;
337     }
338     ExitModuleUpdate();
339 }
340 
OnHmpError(const std::string & hmpName)341 void ModuleUpdateService::OnHmpError(const std::string &hmpName)
342 {
343     LOG(INFO) << "OnHmpError hmpName=" << hmpName;
344     std::string errPath = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
345     if (!CheckPathExists(errPath)) {
346         LOG(INFO) << "No update package in " << hmpName;
347         return;
348     }
349     if (!ForceRemoveDirectory(errPath)) {
350         LOG(ERROR) << "Failed to remove " << errPath;
351         return;
352     }
353     RevertAndReboot();
354 }
355 
BackupActiveModules() const356 bool ModuleUpdateService::BackupActiveModules() const
357 {
358     if (!CheckPathExists(UPDATE_ACTIVE_DIR)) {
359         LOG(INFO) << "Nothing to backup";
360         return true;
361     }
362     if (CheckPathExists(UPDATE_BACKUP_DIR)) {
363         if (!ForceRemoveDirectory(UPDATE_BACKUP_DIR)) {
364             LOG(ERROR) << "Failed to remove backup dir";
365             return false;
366         }
367     }
368     if (!CreateDirIfNeeded(UPDATE_BACKUP_DIR, DIR_MODE)) {
369         LOG(ERROR) << "Failed to create backup dir";
370         return false;
371     }
372 
373     std::vector<std::string> activeFiles;
374     GetDirFiles(UPDATE_ACTIVE_DIR, activeFiles);
375     ON_SCOPE_EXIT(rmdir) {
376         if (!ForceRemoveDirectory(UPDATE_BACKUP_DIR)) {
377             LOG(WARNING) << "Failed to remove backup dir when backup failed";
378         }
379     };
380     for (const auto &file : activeFiles) {
381         if (!BackupFile(file)) {
382             return false;
383         }
384     }
385 
386     CANCEL_SCOPE_EXIT_GUARD(rmdir);
387     return true;
388 }
389 
RevertAndReboot() const390 bool ModuleUpdateService::RevertAndReboot() const
391 {
392     LOG(INFO) << "RevertAndReboot";
393     if (!CheckPathExists(UPDATE_BACKUP_DIR)) {
394         LOG(ERROR) << UPDATE_BACKUP_DIR << " does not exist";
395         return false;
396     }
397     struct stat statData;
398     int ret = stat(UPDATE_ACTIVE_DIR, &statData);
399     if (ret != 0) {
400         LOG(ERROR) << "Failed to access " << UPDATE_ACTIVE_DIR << " err=" << errno;
401         return false;
402     }
403     if (!ForceRemoveDirectory(UPDATE_ACTIVE_DIR)) {
404         LOG(ERROR) << "Failed to remove " << UPDATE_ACTIVE_DIR;
405         return false;
406     }
407 
408     ret = rename(UPDATE_BACKUP_DIR, UPDATE_ACTIVE_DIR);
409     if (ret != 0) {
410         LOG(ERROR) << "Failed to rename " << UPDATE_BACKUP_DIR << " to " << UPDATE_ACTIVE_DIR << " err=" << errno;
411         return false;
412     }
413     ret = chmod(UPDATE_ACTIVE_DIR, statData.st_mode & ALL_PERMISSIONS);
414     if (ret != 0) {
415         LOG(ERROR) << "Failed to restore original permissions for " << UPDATE_ACTIVE_DIR << " err=" << errno;
416         return false;
417     }
418 
419     LOG(INFO) << "Rebooting";
420     Utils::UpdaterDoReboot("");
421     return true;
422 }
423 
ScanPreInstalledHmp()424 void ModuleUpdateService::ScanPreInstalledHmp()
425 {
426     std::vector<std::string> files;
427     GetDirFiles(MODULE_PREINSTALL_DIR, files);
428     for (auto &file : files) {
429         if (!CheckFileSuffix(file, MODULE_PACKAGE_SUFFIX)) {
430             continue;
431         }
432         std::unique_ptr<ModuleFile> moduleFile = ModuleFile::Open(file);
433         if (moduleFile == nullptr) {
434             continue;
435         }
436         std::string hmpName = GetHmpName(file);
437         if (hmpName.empty()) {
438             continue;
439         }
440         hmpSet_.emplace(hmpName);
441         saIdHmpMap_.emplace(moduleFile->GetSaId(), hmpName);
442     }
443 }
444 } // namespace SysInstaller
445 } // namespace OHOS
446