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