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/mount.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <thread>
24 #include <fcntl.h>
25 #include "init_reboot.h"
26 #include "if_system_ability_manager.h"
27 #include "iremote_object.h"
28 #include "iservice_registry.h"
29 #include "directory_ex.h"
30 #include "log/log.h"
31 #include "package/package.h"
32 #include "parameter.h"
33 #include "parameters.h"
34 #include "singleton.h"
35 #include "utils.h"
36 #include "module_constants.h"
37 #include "module_file.h"
38
39 namespace OHOS {
40 namespace SysInstaller {
41 using namespace Updater;
42
43 namespace {
44 constexpr const char *BOOT_COMPLETE_PARAM = "bootevent.boot.completed";
45 constexpr const char *BOOT_SUCCESS_VALUE = "true";
46 constexpr int32_t PARAM_VALUE_SIZE = 10;
47 constexpr std::chrono::milliseconds WAIT_FOR_FILE_TIME(5);
48 constexpr uint32_t BYTE_SIZE = 8;
49 constexpr mode_t ALL_PERMISSIONS = 0777;
50 constexpr const char *PREFIXES[] = {UPDATE_INSTALL_DIR, UPDATE_ACTIVE_DIR, UPDATE_BACKUP_DIR, MODULE_PREINSTALL_DIR};
51 }
52
CreateDirIfNeeded(const std::string & path,mode_t mode)53 bool CreateDirIfNeeded(const std::string &path, mode_t mode)
54 {
55 struct stat statData;
56
57 if (stat(path.c_str(), &statData) != 0) {
58 if (errno == ENOENT) {
59 if (mkdir(path.c_str(), mode) != 0) {
60 LOG(ERROR) << "Could not mkdir " << path;
61 return false;
62 }
63 } else {
64 LOG(ERROR) << "Could not stat " << path;
65 return false;
66 }
67 } else {
68 if (!S_ISDIR(statData.st_mode)) {
69 LOG(ERROR) << path << " exists and is not a directory";
70 return false;
71 }
72 }
73
74 // Need to manually call chmod because mkdir will create a folder with
75 // permissions mode & ~umask.
76 if (chmod(path.c_str(), mode) != 0) {
77 LOG(WARNING) << "Could not chmod " << path;
78 }
79 return true;
80 }
81
CheckPathExists(const std::string & path)82 bool CheckPathExists(const std::string &path)
83 {
84 struct stat buffer;
85 return stat(path.c_str(), &buffer) == 0;
86 }
87
CheckFileSuffix(const std::string & file,const std::string & suffix)88 bool CheckFileSuffix(const std::string &file, const std::string &suffix)
89 {
90 std::size_t pos = file.find_last_of('.');
91 if (pos == std::string::npos) {
92 LOG(ERROR) << "Invalid file name " << file;
93 return false;
94 }
95 std::string fileSuffix = file.substr(pos);
96 return fileSuffix == suffix;
97 }
98
GetFileName(const std::string & file)99 std::string GetFileName(const std::string &file)
100 {
101 std::size_t startPos = file.find_last_of('/') + 1;
102 std::size_t endPos = file.find_last_of('.');
103 return file.substr(startPos, endPos - startPos);
104 }
105
106 // Get hmpName from path such as "/data/module_update_package/hmpName/sa1.zip"
GetHmpName(const std::string & filePath)107 std::string GetHmpName(const std::string &filePath)
108 {
109 std::size_t endPos = filePath.find_last_of('/');
110 if (endPos == std::string::npos) {
111 LOG(ERROR) << "Invalid package path " << filePath;
112 return "";
113 }
114
115 std::size_t startPos = 0;
116 for (auto &iter : PREFIXES) {
117 if (StartsWith(filePath, iter)) {
118 startPos = strlen(iter) + 1;
119 break;
120 }
121 }
122 if (startPos == 0 || startPos >= endPos) {
123 LOG(ERROR) << "Invalid package path " << filePath;
124 return "";
125 }
126 return filePath.substr(startPos, endPos - startPos);
127 }
128
WaitForFile(const std::string & path,const std::chrono::nanoseconds & timeout)129 bool WaitForFile(const std::string &path, const std::chrono::nanoseconds &timeout)
130 {
131 Timer timer;
132 bool hasSlept = false;
133 while (timer.duration() < timeout) {
134 struct stat buffer;
135 if (stat(path.c_str(), &buffer) != -1) {
136 if (hasSlept) {
137 LOG(INFO) << "wait for '" << path << "' took " << timer;
138 }
139 return true;
140 }
141 std::this_thread::sleep_for(WAIT_FOR_FILE_TIME);
142 hasSlept = true;
143 }
144 LOG(ERROR) << "wait for '" << path << "' timed out and took " << timer;
145 return false;
146 }
147
StartsWith(const std::string & str,const std::string & prefix)148 bool StartsWith(const std::string &str, const std::string &prefix)
149 {
150 return str.substr(0, prefix.size()) == prefix;
151 }
152
ReadFullyAtOffset(int fd,uint8_t * data,size_t count,off_t offset)153 bool ReadFullyAtOffset(int fd, uint8_t *data, size_t count, off_t offset)
154 {
155 while (count > 0) {
156 ssize_t readSize = pread(fd, data, count, offset);
157 if (readSize <= 0) {
158 return false;
159 }
160 data += readSize;
161 count -= static_cast<size_t>(readSize);
162 offset += readSize;
163 }
164 return true;
165 }
166
WriteFullyAtOffset(int fd,const uint8_t * data,size_t count,off_t offset)167 bool WriteFullyAtOffset(int fd, const uint8_t *data, size_t count, off_t offset)
168 {
169 while (count > 0) {
170 ssize_t writeSize = pwrite(fd, data, count, offset);
171 if (writeSize <= 0) {
172 return false;
173 }
174 data += writeSize;
175 count -= static_cast<size_t>(writeSize);
176 offset += writeSize;
177 }
178 return true;
179 }
180
ReadLE16(const uint8_t * buff)181 uint16_t ReadLE16(const uint8_t *buff)
182 {
183 if (buff == nullptr) {
184 LOG(ERROR) << "buff is null";
185 return 0;
186 }
187 uint16_t value16 = buff[0];
188 value16 += static_cast<uint16_t>(buff[1] << BYTE_SIZE);
189 return value16;
190 }
191
ReadLE32(const uint8_t * buff)192 uint32_t ReadLE32(const uint8_t *buff)
193 {
194 if (buff == nullptr) {
195 LOG(ERROR) << "buff is null";
196 return 0;
197 }
198 uint16_t low = ReadLE16(buff);
199 uint16_t high = ReadLE16(buff + sizeof(uint16_t));
200 uint32_t value = ((static_cast<uint32_t>(high)) << (BYTE_SIZE * sizeof(uint16_t))) | low;
201 return value;
202 }
203
operator <<(std::ostream & os,const Timer & timer)204 std::ostream &operator<<(std::ostream &os, const Timer &timer)
205 {
206 os << timer.duration().count() << "ms";
207 return os;
208 }
209
GetRealPath(const std::string & filePath)210 std::string GetRealPath(const std::string &filePath)
211 {
212 char path[PATH_MAX] = {'\0'};
213 if (realpath(filePath.c_str(), path) == nullptr) {
214 LOG(ERROR) << "get real path fail " << filePath;
215 return "";
216 }
217 if (!CheckPathExists(path)) {
218 LOG(ERROR) << "path " << path << " doesn't exist";
219 return "";
220 }
221 std::string realPath(path);
222 return realPath;
223 }
224
MountModuleUpdateDir(void)225 __attribute__((weak)) void MountModuleUpdateDir(void)
226 {
227 LOG(INFO) << "mount /module_update.";
228 if (mount("tmpfs", "/module_update", "tmpfs", MS_NOEXEC | MS_NODEV | MS_NOSUID, "mode=0755") != 0) {
229 LOG(ERROR) << "mount module_Update tmpfs fail, " << strerror(errno);
230 }
231 if (mount(nullptr, "/module_update", nullptr, MS_SHARED, nullptr) != 0) {
232 LOG(ERROR) << "mount module_Update shared fail, " << strerror(errno);
233 }
234 }
235
RevertImageCert(const std::string & hmpName,bool revertMore)236 __attribute__((weak)) bool RevertImageCert(const std::string &hmpName, bool revertMore)
237 {
238 LOG(INFO) << "Revert image cert, default is true";
239 return true;
240 }
241
VerityInfoWrite(const ModuleFile & file)242 __attribute__((weak)) bool VerityInfoWrite(const ModuleFile &file)
243 {
244 LOG(INFO) << "VerityInfoWrite, default is true.";
245 return true;
246 }
247
PrepareFileToDestDir(const std::string & pkgPath,const std::string & outPath)248 __attribute__((weak)) bool PrepareFileToDestDir(const std::string &pkgPath, const std::string &outPath)
249 {
250 if (ExtraPackageDir(pkgPath.c_str(), nullptr, nullptr, outPath.c_str()) != 0) {
251 LOG(ERROR) << "Failed to unpack hmp package " << pkgPath;
252 return false;
253 }
254 return true;
255 }
256
SetModuleVersion(const ModuleFile & file)257 __attribute__((weak)) void SetModuleVersion(const ModuleFile &file)
258 {
259 LOG(INFO) << "Set module version.";
260 }
261
Revert(const std::string & hmpName,bool reboot)262 void Revert(const std::string &hmpName, bool reboot)
263 {
264 LOG(INFO) << "RevertAndReboot, reboot: " << reboot << "; hmpName: " << hmpName;
265 std::string installPath = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
266 if (CheckPathExists(installPath)) {
267 if (!ForceRemoveDirectory(installPath)) {
268 LOG(ERROR) << "Failed to remove installPath: " << installPath << " err=" << errno;
269 return;
270 }
271 }
272 struct stat statData;
273 std::string activePath = std::string(UPDATE_ACTIVE_DIR) + "/" + hmpName;
274 int ret = stat(activePath.c_str(), &statData);
275 if (ret != 0) {
276 LOG(ERROR) << "Failed to access " << activePath << " err=" << errno;
277 return;
278 }
279 if (!ForceRemoveDirectory(activePath)) {
280 LOG(ERROR) << "Failed to remove " << activePath << " err=" << errno;
281 return;
282 }
283
284 std::string backupPath = std::string(UPDATE_BACKUP_DIR) + "/" + hmpName;
285 if (CheckPathExists(backupPath)) {
286 ret = rename(backupPath.c_str(), activePath.c_str());
287 if (ret != 0) {
288 LOG(ERROR) << "Failed to rename " << backupPath << " to " << activePath << " err=" << errno;
289 }
290 if (ret == 0 && chmod(activePath.c_str(), statData.st_mode & ALL_PERMISSIONS) != 0) {
291 LOG(ERROR) << "Failed to restore original permissions for " << activePath << " err=" << errno;
292 }
293 }
294 RevertImageCert(hmpName, true);
295 sync();
296 if (reboot) {
297 LOG(INFO) << "Rebooting";
298 DoReboot("module_update revert.");
299 }
300 }
301
IsHotSa(int32_t saId)302 bool IsHotSa(int32_t saId)
303 {
304 std::vector<int32_t> onDemandSaIds;
305 sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
306 if (samgr == nullptr) {
307 LOG(ERROR) << "get system ability manager error";
308 return false;
309 }
310 samgr->GetOnDemandSystemAbilityIds(onDemandSaIds);
311 if (onDemandSaIds.empty()) {
312 LOG(ERROR) << "get ondemand saIds fail";
313 return false;
314 }
315 if (find(onDemandSaIds.begin(), onDemandSaIds.end(), saId) == onDemandSaIds.end()) {
316 LOG(INFO) << "this is not an ondemand sa, saId=" << saId;
317 return false;
318 }
319 return true;
320 }
321
IsRunning(int32_t saId)322 bool IsRunning(int32_t saId)
323 {
324 sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
325 if (samgr == nullptr) {
326 LOG(ERROR) << "get system ability manager error";
327 return false;
328 }
329 auto object = samgr->CheckSystemAbility(saId);
330 if (object == nullptr) {
331 LOG(INFO) << "sa not exists, saId=" << saId;
332 return false;
333 }
334 return true;
335 }
336
CheckBootComplete(void)337 bool CheckBootComplete(void)
338 {
339 char value[PARAM_VALUE_SIZE] = "";
340 int ret = GetParameter(BOOT_COMPLETE_PARAM, "", value, PARAM_VALUE_SIZE);
341 if (ret < 0) {
342 LOG(ERROR) << "Failed to get parameter " << BOOT_COMPLETE_PARAM;
343 return false;
344 }
345 return strcmp(value, BOOT_SUCCESS_VALUE) == 0;
346 }
347
GetDeviceSaSdkVersion(void)348 std::string GetDeviceSaSdkVersion(void)
349 {
350 std::string sdkVersion = system::GetParameter("const.build.sa_sdk_version", "");
351 if (sdkVersion.empty()) {
352 LOG(ERROR) << "get device sa sdk version failed.";
353 return sdkVersion;
354 }
355 return sdkVersion;
356 }
357
GetDeviceApiVersion(void)358 int GetDeviceApiVersion(void)
359 {
360 std::string apiVersion = system::GetParameter("const.ohos.apiversion", "");
361 if (apiVersion.empty()) {
362 LOG(ERROR) << "get device api version failed.";
363 return 0;
364 }
365 return Utils::String2Int<int>(apiVersion, Utils::N_DEC);
366 }
367
GetContentFromZip(const std::string & zipPath,const std::string & fileName)368 std::string GetContentFromZip(const std::string &zipPath, const std::string &fileName)
369 {
370 ModuleZipHelper helper(zipPath);
371 if (!helper.IsValid()) {
372 LOG(ERROR) << "Failed to open file: " << zipPath;
373 return "";
374 }
375 std::string content;
376 if (!ExtractZipFile(helper, fileName, content)) {
377 LOG(ERROR) << "Failed to extract: " << fileName << " from package: " << zipPath;
378 return "";
379 }
380 return content;
381 }
382
RemoveSpecifiedDir(const std::string & path,bool keepDir)383 bool RemoveSpecifiedDir(const std::string &path, bool keepDir)
384 {
385 if (!CheckPathExists(path)) {
386 return false;
387 }
388 LOG(INFO) << "Clear specified dir: " << path << "; keepdir: " << keepDir;
389 if (!keepDir) {
390 if (!ForceRemoveDirectory(path)) {
391 LOG(WARNING) << "Failed to remove: " << path << ", err: " << errno;
392 return false;
393 }
394 return true;
395 }
396 if (!std::filesystem::is_directory(path)) {
397 LOG(WARNING) << "The file is not a directory: " << path.c_str();
398 return false;
399 }
400 bool ret = true;
401 for (const auto &entry : std::filesystem::directory_iterator(path)) {
402 std::error_code errorCode;
403 LOG(INFO) << "deleted " << entry.path().c_str() << ";";
404 if (!std::filesystem::remove_all(entry.path(), errorCode)) {
405 LOG(ERROR) << "Failed to deleted " << entry.path().c_str() << "; errorCode: " << errorCode.value();
406 ret = false;
407 }
408 }
409 return ret;
410 }
411
CheckAndUpdateRevertResult(const std::string & hmpPath,const std::string & resultInfo,const std::string & keyWord)412 bool CheckAndUpdateRevertResult(const std::string &hmpPath, const std::string &resultInfo, const std::string &keyWord)
413 {
414 if (resultInfo.find(keyWord) == std::string::npos) {
415 return false;
416 }
417 std::ifstream ifs { MODULE_RESULT_PATH };
418 if (!ifs.is_open()) {
419 LOG(ERROR) << "ifs open result_file fail" << strerror(errno);
420 return false;
421 }
422 std::string line;
423 std::vector<std::string> lines;
424 bool ret = false;
425 while (getline(ifs, line)) {
426 if (line.find(hmpPath) == std::string::npos) {
427 lines.push_back(line);
428 continue;
429 }
430 std::vector<std::string> results = Utils::SplitString(line, ";");
431 if (results.size() < 3) { // 3: hmp|result|msg
432 LOG(ERROR) << "Split result fail: " << line;
433 continue;
434 }
435 if (results[1] != "0") { // 1: index of result
436 lines.push_back(line);
437 continue;
438 }
439 ret = true;
440 lines.push_back(resultInfo);
441 }
442 ifs.close();
443 std::ofstream outfile(MODULE_RESULT_PATH, std::ios::binary | std::ios::trunc);
444 if (!outfile) {
445 LOG(ERROR) << "ofs open result_file fail" << strerror(errno);
446 return false;
447 }
448 for (const auto &info : lines) {
449 outfile << info;
450 }
451 LOG(INFO) << "Update revert result succ";
452 sync();
453 return ret;
454 }
455
GetCurrentHmpName(void)456 std::string GetCurrentHmpName(void)
457 {
458 std::vector<std::string> files;
459 GetDirFiles(MODULE_PREINSTALL_DIR, files);
460 for (const auto &file : files) {
461 if (!CheckFileSuffix(file, MODULE_PACKAGE_SUFFIX)) {
462 continue;
463 }
464 std::string hmpName = GetHmpName(file);
465 if (hmpName.empty()) {
466 continue;
467 }
468 return hmpName;
469 }
470 return "";
471 }
472
NotifyBmsRevert(const std::string & hmpName,bool record)473 int32_t NotifyBmsRevert(const std::string &hmpName, bool record)
474 {
475 LOG(INFO) << "Start to collect module name which contains hap or hsp";
476 SetParameter(BMS_START_INSTALL, NOTIFY_BMS_REVERT);
477 std::string preInstalledPath = std::string(MODULE_PREINSTALL_DIR) + "/" + hmpName + "/" + HMP_INFO_NAME;
478 std::unique_ptr<ModuleFile> moduleFile = ModuleFile::Open(preInstalledPath);
479 if (moduleFile == nullptr) {
480 LOG(ERROR) << "Invalid preinstalled file " << preInstalledPath;
481 return -1;
482 }
483 int32_t result = 0;
484 std::ostringstream oss;
485 oss << BMS_START_INSTALL << "=" << NOTIFY_BMS_REVERT << "\n";
486 for (const auto &[key, value] : moduleFile->GetVersionInfo().moduleMap) {
487 if (value.bundleInfoList.empty()) {
488 continue;
489 }
490 std::string attr = std::string(BMS_RESULT_PREFIX) + "." + key;
491 if (!record && SetParameter(attr.c_str(), BMS_INSTALL_FAIL) != 0) {
492 LOG(WARNING) << "Failed to set module params: " << attr;
493 result++;
494 }
495 oss << attr << "=" << BMS_INSTALL_FAIL << "\n";
496 }
497 if (record) {
498 WriteStringToFile(MODULE_UPDATE_PARAMS_FILE, oss.str());
499 }
500 return result;
501 }
502
WriteStringToFile(const std::string & filePath,const std::string & content)503 int32_t WriteStringToFile(const std::string &filePath, const std::string &content)
504 {
505 // if file not exist, create file or appead
506 std::ofstream file (filePath, std::ios::app);
507 if (!file.is_open()) {
508 LOG(ERROR) << "open file fail: " << filePath << "; err is " << strerror(errno);
509 return -1;
510 }
511 file << content;
512 if (file.bad()) {
513 LOG(ERROR) << "write to file fail, " << filePath;
514 }
515 file.close();
516 sync();
517 return 0;
518 }
519 } // namespace SysInstaller
520 } // namespace OHOS