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_utils.h"
17 #include <cerrno>
18 #include <cstdio>
19 #include <dirent.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <thread>
23 #include <fcntl.h>
24 #include "init_reboot.h"
25 #include "if_system_ability_manager.h"
26 #include "iremote_object.h"
27 #include "iservice_registry.h"
28 #include "directory_ex.h"
29 #include "log/log.h"
30 #include "parameter.h"
31 #include "parameters.h"
32 #include "singleton.h"
33 #include "utils.h"
34 #include "module_constants.h"
35 #include "module_file.h"
36
37 namespace OHOS {
38 namespace SysInstaller {
39 using namespace Updater;
40
41 namespace {
42 constexpr const char *BOOT_COMPLETE_PARAM = "bootevent.boot.completed";
43 constexpr const char *BOOT_SUCCESS_VALUE = "true";
44 constexpr int32_t PARAM_VALUE_SIZE = 10;
45 constexpr std::chrono::milliseconds WAIT_FOR_FILE_TIME(5);
46 constexpr uint32_t BYTE_SIZE = 8;
47 constexpr mode_t ALL_PERMISSIONS = 0777;
48 constexpr const char *PREFIXES[] = {UPDATE_INSTALL_DIR, UPDATE_ACTIVE_DIR, UPDATE_BACKUP_DIR, MODULE_PREINSTALL_DIR};
49 }
50
CreateDirIfNeeded(const std::string & path,mode_t mode)51 bool CreateDirIfNeeded(const std::string &path, mode_t mode)
52 {
53 struct stat statData;
54
55 if (stat(path.c_str(), &statData) != 0) {
56 if (errno == ENOENT) {
57 if (mkdir(path.c_str(), mode) != 0) {
58 LOG(ERROR) << "Could not mkdir " << path;
59 return false;
60 }
61 } else {
62 LOG(ERROR) << "Could not stat " << path;
63 return false;
64 }
65 } else {
66 if (!S_ISDIR(statData.st_mode)) {
67 LOG(ERROR) << path << " exists and is not a directory";
68 return false;
69 }
70 }
71
72 // Need to manually call chmod because mkdir will create a folder with
73 // permissions mode & ~umask.
74 if (chmod(path.c_str(), mode) != 0) {
75 LOG(WARNING) << "Could not chmod " << path;
76 }
77 return true;
78 }
79
CheckPathExists(const std::string & path)80 bool CheckPathExists(const std::string &path)
81 {
82 struct stat buffer;
83 return stat(path.c_str(), &buffer) == 0;
84 }
85
CheckFileSuffix(const std::string & file,const std::string & suffix)86 bool CheckFileSuffix(const std::string &file, const std::string &suffix)
87 {
88 std::size_t pos = file.find_last_of('.');
89 if (pos == std::string::npos) {
90 LOG(ERROR) << "Invalid file name " << file;
91 return false;
92 }
93 std::string fileSuffix = file.substr(pos);
94 return fileSuffix == suffix;
95 }
96
GetFileName(const std::string & file)97 std::string GetFileName(const std::string &file)
98 {
99 std::size_t startPos = file.find_last_of('/') + 1;
100 std::size_t endPos = file.find_last_of('.');
101 return file.substr(startPos, endPos - startPos);
102 }
103
104 // Get hmpName from path such as "/data/module_update_package/hmpName/sa1.zip"
GetHmpName(const std::string & filePath)105 std::string GetHmpName(const std::string &filePath)
106 {
107 std::size_t endPos = filePath.find_last_of('/');
108 if (endPos == std::string::npos) {
109 LOG(ERROR) << "Invalid package path " << filePath;
110 return "";
111 }
112
113 std::size_t startPos = 0;
114 for (auto &iter : PREFIXES) {
115 if (StartsWith(filePath, iter)) {
116 startPos = strlen(iter) + 1;
117 break;
118 }
119 }
120 if (startPos == 0 || startPos >= endPos) {
121 LOG(ERROR) << "Invalid package path " << filePath;
122 return "";
123 }
124 return filePath.substr(startPos, endPos - startPos);
125 }
126
WaitForFile(const std::string & path,const std::chrono::nanoseconds & timeout)127 bool WaitForFile(const std::string &path, const std::chrono::nanoseconds &timeout)
128 {
129 Timer timer;
130 bool hasSlept = false;
131 while (timer.duration() < timeout) {
132 struct stat buffer;
133 if (stat(path.c_str(), &buffer) != -1) {
134 if (hasSlept) {
135 LOG(INFO) << "wait for '" << path << "' took " << timer;
136 }
137 return true;
138 }
139 std::this_thread::sleep_for(WAIT_FOR_FILE_TIME);
140 hasSlept = true;
141 }
142 LOG(ERROR) << "wait for '" << path << "' timed out and took " << timer;
143 return false;
144 }
145
StartsWith(const std::string & str,const std::string & prefix)146 bool StartsWith(const std::string &str, const std::string &prefix)
147 {
148 return str.substr(0, prefix.size()) == prefix;
149 }
150
ReadFullyAtOffset(int fd,uint8_t * data,size_t count,off_t offset)151 bool ReadFullyAtOffset(int fd, uint8_t *data, size_t count, off_t offset)
152 {
153 while (count > 0) {
154 ssize_t readSize = pread(fd, data, count, offset);
155 if (readSize <= 0) {
156 return false;
157 }
158 data += readSize;
159 count -= static_cast<size_t>(readSize);
160 offset += readSize;
161 }
162 return true;
163 }
164
ReadLE16(const uint8_t * buff)165 uint16_t ReadLE16(const uint8_t *buff)
166 {
167 if (buff == nullptr) {
168 LOG(ERROR) << "buff is null";
169 return 0;
170 }
171 uint16_t value16 = buff[0];
172 value16 += static_cast<uint16_t>(buff[1] << BYTE_SIZE);
173 return value16;
174 }
175
ReadLE32(const uint8_t * buff)176 uint32_t ReadLE32(const uint8_t *buff)
177 {
178 if (buff == nullptr) {
179 LOG(ERROR) << "buff is null";
180 return 0;
181 }
182 uint16_t low = ReadLE16(buff);
183 uint16_t high = ReadLE16(buff + sizeof(uint16_t));
184 uint32_t value = ((static_cast<uint32_t>(high)) << (BYTE_SIZE * sizeof(uint16_t))) | low;
185 return value;
186 }
187
operator <<(std::ostream & os,const Timer & timer)188 std::ostream &operator<<(std::ostream &os, const Timer &timer)
189 {
190 os << timer.duration().count() << "ms";
191 return os;
192 }
193
GetRealPath(const std::string & filePath)194 std::string GetRealPath(const std::string &filePath)
195 {
196 char path[PATH_MAX] = {'\0'};
197 if (realpath(filePath.c_str(), path) == nullptr) {
198 LOG(ERROR) << "get real path fail " << filePath;
199 return "";
200 }
201 if (!CheckPathExists(path)) {
202 LOG(ERROR) << "path " << path << " doesn't exist";
203 return "";
204 }
205 std::string realPath(path);
206 return realPath;
207 }
208
Revert(const std::string & hmpName,bool reboot)209 void Revert(const std::string &hmpName, bool reboot)
210 {
211 LOG(INFO) << "RevertAndReboot, reboot: " << reboot;
212 std::string installPath = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
213 if (CheckPathExists(installPath)) {
214 if (!ForceRemoveDirectory(installPath)) {
215 LOG(ERROR) << "Failed to remove installPath: " << installPath;
216 return;
217 }
218 }
219 struct stat statData;
220 std::string activePath = std::string(UPDATE_ACTIVE_DIR) + "/" + hmpName;
221 int ret = stat(activePath.c_str(), &statData);
222 if (ret != 0) {
223 LOG(ERROR) << "Failed to access " << activePath << " err=" << errno;
224 return;
225 }
226 if (!ForceRemoveDirectory(activePath)) {
227 LOG(ERROR) << "Failed to remove " << activePath;
228 return;
229 }
230
231 std::string backupPath = std::string(UPDATE_BACKUP_DIR) + "/" + hmpName;
232 if (CheckPathExists(backupPath)) {
233 ret = rename(backupPath.c_str(), activePath.c_str());
234 if (ret != 0) {
235 LOG(ERROR) << "Failed to rename " << backupPath << " to " << activePath << " err=" << errno;
236 }
237 if (ret == 0 && chmod(activePath.c_str(), statData.st_mode & ALL_PERMISSIONS) != 0) {
238 LOG(ERROR) << "Failed to restore original permissions for " << activePath << " err=" << errno;
239 }
240 }
241 sync();
242 if (reboot) {
243 LOG(INFO) << "Rebooting";
244 DoReboot("");
245 }
246 }
247
IsHotSa(int32_t saId)248 bool IsHotSa(int32_t saId)
249 {
250 std::vector<int32_t> onDemandSaIds;
251 sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
252 if (samgr == nullptr) {
253 LOG(ERROR) << "get system ability manager error";
254 return false;
255 }
256 samgr->GetOnDemandSystemAbilityIds(onDemandSaIds);
257 if (onDemandSaIds.empty()) {
258 LOG(ERROR) << "get ondemand saIds fail";
259 return false;
260 }
261 if (find(onDemandSaIds.begin(), onDemandSaIds.end(), saId) == onDemandSaIds.end()) {
262 LOG(INFO) << "this is not an ondemand sa, saId=" << saId;
263 return false;
264 }
265 return true;
266 }
267
IsRunning(int32_t saId)268 bool IsRunning(int32_t saId)
269 {
270 sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
271 if (samgr == nullptr) {
272 LOG(ERROR) << "get system ability manager error";
273 return false;
274 }
275 auto object = samgr->CheckSystemAbility(saId);
276 if (object == nullptr) {
277 LOG(INFO) << "sa not exists, saId=" << saId;
278 return false;
279 }
280 return true;
281 }
282
CheckBootComplete(void)283 bool CheckBootComplete(void)
284 {
285 char value[PARAM_VALUE_SIZE] = "";
286 int ret = GetParameter(BOOT_COMPLETE_PARAM, "", value, PARAM_VALUE_SIZE);
287 if (ret < 0) {
288 LOG(ERROR) << "Failed to get parameter " << BOOT_COMPLETE_PARAM;
289 return false;
290 }
291 return strcmp(value, BOOT_SUCCESS_VALUE) == 0;
292 }
293
IsHotHmpPackage(int32_t type)294 bool IsHotHmpPackage(int32_t type)
295 {
296 return false;
297 }
298
IsHotHmpPackage(const std::string & hmpName)299 bool IsHotHmpPackage(const std::string &hmpName)
300 {
301 std::string preInstalledPath = std::string(MODULE_PREINSTALL_DIR) + "/" + hmpName + "/" + HMP_INFO_NAME;
302 if (!Utils::IsFileExist(preInstalledPath)) {
303 LOG(ERROR) << "preInstalled hmp is not exist: " << preInstalledPath;
304 return false;
305 }
306 std::unique_ptr<ModuleFile> preInstalledFile = ModuleFile::Open(preInstalledPath);
307 if (preInstalledFile == nullptr) {
308 LOG(ERROR) << "preInstalled file is invalid: " << preInstalledPath;
309 return false;
310 }
311 return IsHotHmpPackage(static_cast<int32_t>(preInstalledFile->GetHmpPackageType()));
312 }
313
GetDeviceSaSdkVersion(void)314 std::string GetDeviceSaSdkVersion(void)
315 {
316 std::string sdkVersion = system::GetParameter("const.build.sa_sdk_version", "");
317 if (sdkVersion.empty()) {
318 LOG(ERROR) << "get device sa sdk version failed.";
319 return sdkVersion;
320 }
321 return sdkVersion;
322 }
323
GetDeviceApiVersion(void)324 int GetDeviceApiVersion(void)
325 {
326 std::string apiVersion = system::GetParameter("const.ohos.apiversion", "");
327 if (apiVersion.empty()) {
328 LOG(ERROR) << "get device api version failed.";
329 return 0;
330 }
331 return Utils::String2Int<int>(apiVersion, Utils::N_DEC);
332 }
333
GetContentFromZip(const std::string & zipPath,const std::string & fileName)334 std::string GetContentFromZip(const std::string &zipPath, const std::string &fileName)
335 {
336 ModuleZipHelper helper(zipPath);
337 if (!helper.IsValid()) {
338 LOG(ERROR) << "Failed to open file: " << zipPath;
339 return "";
340 }
341 std::string content;
342 if (!ExtractZipFile(helper, fileName, content)) {
343 LOG(ERROR) << "Failed to extract: " << fileName << " from package: " << zipPath;
344 return "";
345 }
346 return content;
347 }
348
RemoveSpecifiedDir(const std::string & path)349 void RemoveSpecifiedDir(const std::string &path)
350 {
351 if (!CheckPathExists(path)) {
352 return;
353 }
354 LOG(INFO) << "Remove specified dir: " << path;
355 if (!ForceRemoveDirectory(path)) {
356 LOG(ERROR) << "Failed to remove: " << path << ", err: " << errno;
357 }
358 }
359
CheckAndUpdateRevertResult(const std::string & hmpPath,const std::string & resultInfo,const std::string & keyWord)360 bool CheckAndUpdateRevertResult(const std::string &hmpPath, const std::string &resultInfo, const std::string &keyWord)
361 {
362 if (resultInfo.find(keyWord) == std::string::npos) {
363 return false;
364 }
365 std::ifstream ifs { MODULE_RESULT_PATH };
366 if (!ifs.is_open()) {
367 LOG(ERROR) << "ifs open result_file fail" << strerror(errno);
368 return false;
369 }
370 std::string line;
371 std::vector<std::string> lines;
372 bool ret = false;
373 while (getline(ifs, line)) {
374 if (line.find(hmpPath) == std::string::npos) {
375 lines.push_back(line);
376 continue;
377 }
378 std::vector<std::string> results = Utils::SplitString(line, ";");
379 if (results.size() < 3) { // 3: hmp|result|msg
380 LOG(ERROR) << "Split result fail: " << line;
381 continue;
382 }
383 if (results[1] != "0") { // 1: index of result
384 lines.push_back(line);
385 continue;
386 }
387 ret = true;
388 lines.push_back(resultInfo);
389 }
390 ifs.close();
391 std::ofstream outfile(MODULE_RESULT_PATH, std::ios::binary | std::ios::trunc);
392 if (!outfile) {
393 LOG(ERROR) << "ofs open result_file fail" << strerror(errno);
394 return false;
395 }
396 for (const auto &info : lines) {
397 outfile << info;
398 }
399 LOG(INFO) << "Update revert result succ";
400 sync();
401 return ret;
402 }
403
KillProcessOnArkWeb(void)404 void KillProcessOnArkWeb(void)
405 {
406 }
407
InstallHmpBundle(const std::string & hmpPath,bool revert)408 bool InstallHmpBundle(const std::string &hmpPath, bool revert)
409 {
410 LOG(INFO) << "Start to install hmp bundle: " << hmpPath << " ,revert: " << revert;
411 return false;
412 }
413 } // namespace SysInstaller
414 } // namespace OHOS