• 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.h"
17 
18 #include <chrono>
19 #include <sys/mount.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 
23 #include "directory_ex.h"
24 #include "log/log.h"
25 #include "module_constants.h"
26 #include "module_dm.h"
27 #include "module_error_code.h"
28 #include "module_file_repository.h"
29 #include "module_loop.h"
30 #include "module_update_kits.h"
31 #include "module_utils.h"
32 #include "parse_util.h"
33 #include "scope_guard.h"
34 #include "string_ex.h"
35 #include "utils.h"
36 
37 namespace OHOS {
38 namespace SysInstaller {
39 using namespace Updater;
40 using std::string;
41 
42 namespace {
43 constexpr mode_t MOUNT_POINT_MODE = 0755;
44 constexpr int32_t LOOP_DEVICE_SETUP_ATTEMPTS = 3;
45 constexpr int32_t RETRY_TIMES_FOR_MODULE_UPDATE_SERVICE = 10;
46 constexpr std::chrono::milliseconds MILLISECONDS_WAITING_MODULE_UPDATE_SERVICE(100);
47 
CreateLoopDevice(const string & path,const ImageStat & imageStat,Loop::LoopbackDeviceUniqueFd & loopbackDevice)48 bool CreateLoopDevice(const string &path, const ImageStat &imageStat, Loop::LoopbackDeviceUniqueFd &loopbackDevice)
49 {
50     for (int32_t attempts = 1; attempts <= LOOP_DEVICE_SETUP_ATTEMPTS; ++attempts) {
51         std::unique_ptr<Loop::LoopbackDeviceUniqueFd> device =
52             Loop::CreateLoopDevice(path, imageStat.imageOffset, imageStat.imageSize);
53         if (device != nullptr) {
54             loopbackDevice = std::move(*device);
55             break;
56         }
57     }
58     return loopbackDevice.deviceFd.Get() != -1;
59 }
60 
StageUpdateModulePackage(const string & updatePath,const string & stagePath)61 bool StageUpdateModulePackage(const string &updatePath, const string &stagePath)
62 {
63     int ret = 0;
64     if (CheckPathExists(stagePath)) {
65         LOG(INFO) << stagePath << " already exists. Deleting";
66         ret = unlink(stagePath.c_str());
67         if (ret != 0) {
68             LOG(ERROR) << "Failed to unlink " << stagePath;
69             return false;
70         }
71     }
72     string path = ExtractFilePath(stagePath);
73     if (!CheckPathExists(path)) {
74         LOG(ERROR) << path << " doesn't exist.";
75         return false;
76     }
77     ret = link(updatePath.c_str(), stagePath.c_str());
78     if (ret != 0) {
79         LOG(ERROR) << "Unable to link " << updatePath << " to " << stagePath;
80         return false;
81     }
82     return true;
83 }
84 
GetLatestUpdateModulePackage(const int32_t saId)85 std::unique_ptr<ModuleFile> GetLatestUpdateModulePackage(const int32_t saId)
86 {
87     auto &instance = ModuleFileRepository::GetInstance();
88     std::unique_ptr<ModuleFile> activeModuleFile = instance.GetModuleFile(UPDATE_ACTIVE_DIR, saId);
89     std::unique_ptr<ModuleFile> updateModuleFile = instance.GetModuleFile(UPDATE_INSTALL_DIR, saId);
90     std::unique_ptr<ModuleFile> ret = nullptr;
91     if (updateModuleFile != nullptr) {
92         if (activeModuleFile == nullptr || ModuleFile::CompareVersion(*updateModuleFile, *activeModuleFile)) {
93             string updatePath = updateModuleFile->GetPath();
94             string activePath = UPDATE_ACTIVE_DIR +
95                 updatePath.substr(strlen(UPDATE_INSTALL_DIR), updatePath.length());
96             if (!StageUpdateModulePackage(updatePath, activePath)) {
97                 return ret;
98             }
99             updateModuleFile->SetPath(activePath);
100             ret = std::move(updateModuleFile);
101         }
102     }
103     if (ret == nullptr && activeModuleFile != nullptr) {
104         ret = std::move(activeModuleFile);
105     }
106     return ret;
107 }
108 
GetSuccessSaIdString(const ModuleUpdateStatus & status)109 string GetSuccessSaIdString(const ModuleUpdateStatus &status)
110 {
111     string ret = "";
112     for (const SaStatus &saStatus : status.saStatusList) {
113         if (saStatus.isMountSuccess) {
114             ret += std::to_string(saStatus.saId) + " ";
115         }
116     }
117     return ret;
118 }
119 }
120 
CheckModuleUpdate(const string & path)121 string ModuleUpdate::CheckModuleUpdate(const string &path)
122 {
123     LOG(INFO) << "CheckModuleUpdate path=" << path;
124     Timer timer;
125     string ret = "";
126     if (!ParseSaProfiles(path)) {
127         LOG(ERROR) << "Failed to parse sa profile";
128         return ret;
129     }
130     ModuleFileRepository::GetInstance().InitRepository(saIdSet_);
131     ON_SCOPE_EXIT(clear) {
132         ModuleFileRepository::GetInstance().Clear();
133     };
134     PrepareModuleFileList();
135     if (moduleFileList_.empty()) {
136         LOG(INFO) << "No module needs to activate";
137         return ret;
138     }
139     if (!Loop::PreAllocateLoopDevices(moduleFileList_.size())) {
140         LOG(ERROR) << "Failed to pre allocate loop devices";
141         return ret;
142     }
143     if (!ActivateModules()) {
144         LOG(ERROR) << "Failed to activate modules";
145         return ret;
146     }
147     ret = GetSuccessSaIdString(status_);
148     LOG(INFO) << "CheckModuleUpdate done, duration=" << timer << ", ret=" << ret;
149     return ret;
150 }
151 
ParseSaProfiles(const string & path)152 bool ModuleUpdate::ParseSaProfiles(const string &path)
153 {
154     string realProfilePath = "";
155     if (!PathToRealPath(path, realProfilePath)) {
156         LOG(ERROR) << "Failed to get real path " << path;
157         return false;
158     }
159     ParseUtil parser;
160     if (!parser.ParseSaProfiles(realProfilePath)) {
161         LOG(ERROR) << "ParseSaProfiles failed! path=" << realProfilePath;
162         return false;
163     }
164     status_.process = Str16ToStr8(parser.GetProcessName());
165     auto saInfos = parser.GetAllSaProfiles();
166     for (const auto &saInfo : saInfos) {
167         saIdSet_.insert(saInfo.saId);
168     }
169     return true;
170 }
171 
PrepareModuleFileList()172 void ModuleUpdate::PrepareModuleFileList()
173 {
174     for (int32_t saId : saIdSet_) {
175         auto &instance = ModuleFileRepository::GetInstance();
176         std::unique_ptr<ModuleFile> systemModuleFile = instance.GetModuleFile(MODULE_PREINSTALL_DIR, saId);
177         if (systemModuleFile == nullptr) {
178             LOG(ERROR) << "Failed to get preinstalled sa " << saId;
179             continue;
180         }
181         std::unique_ptr<ModuleFile> latestModuleFile = GetLatestUpdateModulePackage(saId);
182         if (latestModuleFile != nullptr && ModuleFile::CompareVersion(*latestModuleFile, *systemModuleFile)) {
183             moduleFileList_.emplace_back(std::move(*latestModuleFile));
184         } else {
185             moduleFileList_.emplace_back(std::move(*systemModuleFile));
186         }
187     }
188 }
189 
ActivateModules()190 bool ModuleUpdate::ActivateModules()
191 {
192     bool activateSuccess = true;
193     for (const auto &moduleFile : moduleFileList_) {
194         if (!moduleFile.GetImageStat().has_value()) {
195             LOG(INFO) << moduleFile.GetPath() << " is empty module package";
196             continue;
197         }
198         SaStatus saStatus;
199         saStatus.saId = moduleFile.GetSaId();
200         saStatus.isPreInstalled = ModuleFileRepository::GetInstance().IsPreInstalledModule(moduleFile);
201         saStatus.isMountSuccess = MountModulePackage(moduleFile, !saStatus.isPreInstalled);
202         if (!saStatus.isMountSuccess) {
203             LOG(ERROR) << "Failed to mount module package " << moduleFile.GetPath();
204             activateSuccess = false;
205         }
206         status_.saStatusList.emplace_back(std::move(saStatus));
207     }
208     ReportMountStatus(status_);
209     return activateSuccess;
210 }
211 
MountModulePackage(const ModuleFile & moduleFile,const bool mountOnVerity) const212 bool ModuleUpdate::MountModulePackage(const ModuleFile &moduleFile, const bool mountOnVerity) const
213 {
214     string mountPoint = string(MODULE_ROOT_DIR) + "/" + std::to_string(moduleFile.GetSaId());
215     LOG(INFO) << "Creating mount point: " << mountPoint;
216     Timer timer;
217     int ret = 0;
218     if (!CreateDirIfNeeded(mountPoint, MOUNT_POINT_MODE)) {
219         LOG(ERROR) << "Could not create mount point " << mountPoint << " errno: " << errno;
220         return false;
221     }
222     ON_SCOPE_EXIT(rmDir) {
223         ret = rmdir(mountPoint.c_str());
224         if (ret != 0) {
225             LOG(WARNING) << "Could not rmdir " << mountPoint << " errno: " << errno;
226         }
227     };
228     if (!IsEmptyFolder(mountPoint)) {
229         LOG(ERROR) << mountPoint << " is not empty";
230         return false;
231     }
232     const string &fullPath = moduleFile.GetPath();
233     if (!moduleFile.GetImageStat().has_value()) {
234         LOG(ERROR) << "Could not mount empty module package " << moduleFile.GetPath();
235         return false;
236     }
237     const ImageStat &imageStat = moduleFile.GetImageStat().value();
238     Loop::LoopbackDeviceUniqueFd loopbackDevice;
239     if (!CreateLoopDevice(fullPath, imageStat, loopbackDevice)) {
240         LOG(ERROR) << "Could not create loop device for " << fullPath;
241         return false;
242     }
243     LOG(INFO) << "Loopback device created: " << loopbackDevice.name;
244 
245     string blockDevice = loopbackDevice.name;
246     if (mountOnVerity) {
247         if (!CreateDmDevice(moduleFile, blockDevice)) {
248             LOG(ERROR) << "Could not create dm-verity device on " << blockDevice;
249             return false;
250         }
251     }
252     uint32_t mountFlags = MS_NOATIME | MS_NODEV | MS_DIRSYNC | MS_RDONLY;
253     LOG(INFO) << "fsType=" << imageStat.fsType;
254     ret = mount(blockDevice.c_str(), mountPoint.c_str(), imageStat.fsType, mountFlags, nullptr);
255     if (ret != 0) {
256         LOG(ERROR) << "Mounting failed for module package " << fullPath << " errno:" << errno;
257         return false;
258     }
259     LOG(INFO) << "Successfully mounted module package " << fullPath << " on " << mountPoint << " duration=" << timer;
260     loopbackDevice.CloseGood();
261     CANCEL_SCOPE_EXIT_GUARD(rmDir);
262     return true;
263 }
264 
ReportMountStatus(const ModuleUpdateStatus & status) const265 void ModuleUpdate::ReportMountStatus(const ModuleUpdateStatus &status) const
266 {
267     int32_t times = RETRY_TIMES_FOR_MODULE_UPDATE_SERVICE;
268     constexpr int32_t duration = std::chrono::microseconds(MILLISECONDS_WAITING_MODULE_UPDATE_SERVICE).count();
269     while (times > 0) {
270         times--;
271         int32_t ret = ModuleUpdateKits::GetInstance().ReportModuleUpdateStatus(status);
272         if (ret == ModuleErrorCode::ERR_SERVICE_NOT_FOUND) {
273             LOG(INFO) << "retry to report mount failed";
274             usleep(duration);
275         } else {
276             if (ret != ModuleErrorCode::MODULE_UPDATE_SUCCESS) {
277                 LOG(ERROR) << "Failed to report mount failed";
278             }
279             return;
280         }
281     }
282     LOG(ERROR) << "Report mount failed timeout";
283 }
284 } // namespace SysInstaller
285 } // namespace OHOS