/* * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include "applypatch/partition_record.h" #include "flashd/flashd.h" #include "log/log.h" #include "misc_info/misc_info.h" #include "package/pkg_manager.h" #include "securec.h" #include "updater/hardware_fault_retry.h" #include "updater/updater.h" #include "updater/updater_const.h" #include "updater_main.h" #include "utils.h" namespace Updater { using namespace Hpackage; using namespace Updater::Utils; void DeleteInstallTimeFile() { const std::string installTimeFilePath = std::string(UPDATER_PATH) + "/" + std::string(INSTALL_TIME_FILE); if (access(installTimeFilePath.c_str(), F_OK) != -1) { (void)DeleteFile(installTimeFilePath); LOG(INFO) << "delete install time file"; } } bool IsDouble(const std::string& str) { std::regex pattern("^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"); if (!std::regex_match(str, pattern)) { LOG(ERROR) << "match double failed"; return false; } return true; } void WriteInstallTime(UpdaterParams &upParams) { std::ofstream ofs; ofs.open(std::string(UPDATER_PATH) + "/" + std::string(INSTALL_TIME_FILE), std::ios::app | std::ios::out); if (!ofs.is_open()) { LOG(ERROR) << "open install time file fail"; return; } ofs << DurationToString(upParams.installTime, upParams.pkgLocation) << "\n"; } void ReadInstallTime(UpdaterParams &upParams) { std::ifstream ifs; std::string buf; ifs.open(std::string(UPDATER_PATH) + "/" + std::string(INSTALL_TIME_FILE), std::ios::in); if (!ifs.is_open()) { LOG(ERROR) << "read install time file fail"; return; } unsigned int index = 0; while (getline(ifs, buf)) { if (index >= upParams.pkgLocation) { break; } if (IsDouble(buf)) { double timeDistance = 0; if (!Utils::ConvertToDouble(buf, timeDistance)) { LOG(ERROR) << "ConvertToDouble failed"; return; } upParams.installTime[index++] = std::chrono::duration(timeDistance); } else { LOG(ERROR) << "read install time is invalid"; } } } bool DeleteUpdaterPath(const std::string &path) { auto pDir = std::unique_ptr(opendir(path.c_str()), closedir); if (pDir == nullptr) { LOG(INFO) << "Can not open dir"; return true; } bool sdcardTmp = false; if (path.find("sdcard") != std::string::npos) { sdcardTmp = true; } struct dirent *dp = nullptr; while ((dp = readdir(pDir.get())) != nullptr) { std::string currentName(dp->d_name); if (currentName[0] == '.' || (currentName.compare("log") == 0) || (currentName.compare(UPDATER_RESULT_FILE) == 0) || (currentName.compare(UPDATER_LOCALE_FILE) == 0) || (currentName.compare(MODULE_UPDATE_RESULT_FILE) == 0) || (currentName.compare(UPLOAD_LOG_TIME_FILE) == 0) || (currentName.compare(INSTALL_TIME_FILE) == 0) || (currentName.compare(ROLLBACK_FILE) == 0)) { continue; } if (sdcardTmp && currentName.find(SDCARD_PACKAGE_SUFFIX) != std::string::npos) { continue; } std::string tmpName(path); tmpName.append("/" + currentName); if (IsDirExist(tmpName)) { DeleteUpdaterPath(tmpName); } #ifndef UPDATER_UT remove(tmpName.c_str()); #endif } return true; } bool ClearMisc() { struct UpdateMessage cleanBoot {}; if (!WriteUpdaterMiscMsg(cleanBoot)) { LOG(ERROR) << "ClearMisc clear boot message to misc failed"; return false; } auto miscBlockDev = GetBlockDeviceByMountPoint(MISC_PATH); if (miscBlockDev.empty()) { LOG(INFO) << "cannot get block device of partition"; miscBlockDev = MISC_FILE; } LOG(INFO) << "ClearMisc::misc path : " << miscBlockDev; auto fp = std::unique_ptr(fopen(miscBlockDev.c_str(), "rb+"), fclose); if (fp == nullptr) { LOG(ERROR) << "WriteVersionCode fopen failed" << " : " << strerror(errno); return false; } if (fseek(fp.get(), PARTITION_RECORD_OFFSET, SEEK_SET) != 0) { LOG(ERROR) << "ClearMisc fseek failed"; return false; } off_t clearOffset = 0; if (fwrite(&clearOffset, sizeof(off_t), 1, fp.get()) != 1) { LOG(ERROR) << "ClearMisc write misc initOffset 0 failed" << " : " << strerror(errno); return false; } struct PartitionRecordInfo cleanPartition {}; for (size_t tmpOffset = 0; tmpOffset < PARTITION_UPDATER_RECORD_MSG_SIZE; tmpOffset += sizeof(PartitionRecordInfo)) { if (fseek(fp.get(), PARTITION_RECORD_START + tmpOffset, SEEK_SET) != 0) { LOG(ERROR) << "ClearMisc fseek failed"; return false; } if (fwrite(&cleanPartition, sizeof(PartitionRecordInfo), 1, fp.get()) != 1) { LOG(ERROR) << "ClearMisc write misc cleanPartition failed" << " : " << strerror(errno); return false; } } return true; } bool IsSDCardExist(const std::string &sdcardPath) { // Record system error codes. int save_errno = errno; struct stat st {}; if (stat(sdcardPath.c_str(), &st) < 0) { return false; } else { errno = save_errno; return true; } } bool IsMountDataAndSaveLogs(void) { bool isSdCardMode = CheckUpdateMode(SDCARD_MODE); bool isUsbMode = CheckUpdateMode(USB_MODE); bool isSdCardIntralMode = CheckUpdateMode(SDCARD_INTRAL_MODE); bool isLogMounted = GetMountStatusForMountPoint("/log") == MountStatus::MOUNT_MOUNTED; bool isDataAlreadyMounted = GetMountStatusForMountPoint("/data") == MountStatus::MOUNT_MOUNTED; return (!(isSdCardMode || isUsbMode) && (isDataAlreadyMounted || !isLogMounted)) || isSdCardIntralMode; } static void DeleteUpdaterTmpFiles() { if (access(UPDATER_PATH, 0) == 0 && access(SDCARD_CARD_PATH, 0) != 0 && !DeleteUpdaterPath(UPDATER_PATH)) { LOG(ERROR) << "DeleteUpdaterPath failed"; } if (access(SDCARD_CARD_PATH, 0) == 0 && !DeleteUpdaterPath(SDCARD_CARD_PATH)) { LOG(ERROR) << "Delete sdcard path failed"; } if (access(Flashd::FLASHD_FILE_PATH, 0) == 0 && !DeleteUpdaterPath(Flashd::FLASHD_FILE_PATH)) { LOG(ERROR) << "DeleteUpdaterPath failed"; } } void PostUpdater(bool clearMisc) { STAGE(UPDATE_STAGE_BEGIN) << "PostUpdater"; bool isMountDataAndSaveLogs = IsMountDataAndSaveLogs(); (void)SetupPartitions(isMountDataAndSaveLogs); UpdaterInit::GetInstance().InvokeEvent(UPDATER_POST_INIT_EVENT); // clear update misc partition. if (clearMisc && !ClearMisc()) { LOG(ERROR) << "PostUpdater clear misc failed"; } if (!access(COMMAND_FILE, 0) && unlink(COMMAND_FILE) != 0) { LOG(ERROR) << "Delete command failed"; } if (!HardwareFaultRetry::GetInstance().IsRetry()) { DeleteUpdaterTmpFiles(); } if (isMountDataAndSaveLogs) { SaveLogs(); } } void BootMode::InitMode(void) const { InitLogger(modeName); #ifdef UPDATER_BUILD_VARIANT_USER SetLogLevel(INFO); #else SetLogLevel(DEBUG); #endif LoadFstab(); STAGE(UPDATE_STAGE_OUT) << "Start " << modeName; SetParameter(modePara.c_str(), "1"); } bool IsUpdater(const UpdateMessage &boot) { return !IsFlashd(boot) && strncmp(boot.command, "boot_updater", sizeof("boot_updater") - 1) == 0; } bool IsFlashd(const UpdateMessage &boot) { return strncmp(boot.update, "boot_flash", sizeof("boot_flash") - 1) == 0; } std::vector &GetBootModes(void) { static std::vector bootModes {}; return bootModes; } void RegisterMode(const BootMode &mode) { GetBootModes().push_back(mode); } std::optional SelectMode(const UpdateMessage &boot) { const auto &modes = GetBootModes(); // select modes by bootMode.cond which would check misc message auto it = std::find_if(modes.begin(), modes.end(), [&boot] (const auto &bootMode) { if (bootMode.cond != nullptr && bootMode.cond(boot)) { LOG(INFO) << "condition for mode " << bootMode.modeName << " is satisfied"; return true; } LOG(WARNING) << "condition for mode " << bootMode.modeName << " is not satisfied"; return false; }); // misc check failed for each mode, then enter updater mode if (it == modes.end() || it->entryFunc == nullptr) { LOG(WARNING) << "find valid mode failed, enter updater Mode"; return std::nullopt; } LOG(INFO) << "enter " << it->modeName << " mode"; return *it; } bool SetCpuAffinityByPid(const UpdaterParams &upParams, unsigned int reservedCores) { static std::mutex setAffinityLock; std::lock_guard lock(setAffinityLock); std::vector binaryTids = upParams.binaryTids; if (upParams.binaryPid == -1 || std::find( binaryTids.begin(), binaryTids.end(), std::to_string(upParams.binaryPid)) == binaryTids.end()) { LOG(WARNING) << "invalid binaryPid:" << upParams.binaryPid; return false; } unsigned int coreCount = std::thread::hardware_concurrency(); LOG(INFO) << "coreCount:" << coreCount << ", reservedCores:" << reservedCores; if (coreCount <= reservedCores) { LOG(WARNING) << "coreCount:" << coreCount << " <= " << reservedCores; return false; } cpu_set_t mask; CPU_ZERO(&mask); for (unsigned int i = 0; i < coreCount - reservedCores; i++) { CPU_SET(i, &mask); } int syscallRes; for (auto &str : binaryTids) { int32_t temp = -1; if (!Utils::ConvertToLong(str, temp)) { LOG(ERROR) << "ConvertToLong failed:" << str; continue; } pid_t tid = static_cast(temp); syscallRes = syscall(__NR_sched_setaffinity, tid, sizeof(mask), &mask); LOG(INFO) << "setaffinity tid:" << tid; if (syscallRes != 0) { LOG(ERROR) << "set affinity faild:" << syscallRes; } } return true; } void UpdateBinaryTids(const std::vector &output, UpdaterParams &upParams) { if (output.size() < DEFAULT_PROCESS_NUM) { LOG(ERROR) << "check output fail"; return; } auto outputInfo = Trim(output[1]); LOG(INFO) << "binary tids:" << outputInfo; upParams.binaryTids = SplitString(outputInfo, ","); if (upParams.isLoadReduction) { unsigned int coreCount = std::thread::hardware_concurrency(); unsigned int reservedCores = coreCount - LITTLE_CPU_CORES; SetCpuAffinityByPid(upParams, reservedCores); } } } // namespace Updater