/* * Copyright (c) 2021 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 "applypatch/transfer_manager.h" #include #include #include #include #include "applypatch/command_function.h" #include "log/log.h" #include "utils.h" namespace Updater { using namespace Updater::Utils; static TransferManagerPtr g_transferManagerInstance = nullptr; TransferManagerPtr TransferManager::GetTransferManagerInstance() { if (g_transferManagerInstance == nullptr) { g_transferManagerInstance = new TransferManager(); g_transferManagerInstance->Init(); } return g_transferManagerInstance; } void TransferManager::ReleaseTransferManagerInstance(TransferManagerPtr transferManager) { delete transferManager; g_transferManagerInstance = nullptr; transferManager = nullptr; } TransferManager::~TransferManager() { if (globalParams != nullptr) { if (globalParams->writerThreadInfo != nullptr) { globalParams->writerThreadInfo.reset(); } globalParams.reset(); } } bool TransferManager::CommandsExecute(int fd, Command &cmd) { cmd.SetFileDescriptor(fd); std::unique_ptr cf = CommandFunctionFactory::GetCommandFunction(cmd.GetCommandType()); if (cf == nullptr) { LOG(ERROR) << "Failed to get cmd exec"; return false; } CommandResult ret = cf->Execute(cmd); CommandFunctionFactory::ReleaseCommandFunction(cf); if (!CheckResult(ret, cmd.GetCommandLine(), cmd.GetCommandType())) { return false; } return true; } bool TransferManager::CommandsParser(int fd, const std::vector &context) { if (context.size() < 1) { LOG(ERROR) << "too small context in transfer file"; return false; } if (globalParams == nullptr) { LOG(ERROR) << "globalParams is nullptr"; return false; } std::vector::const_iterator ct = context.begin(); globalParams->version = Utils::String2Int(*ct++, Utils::N_DEC); globalParams->blockCount = Utils::String2Int(*ct++, Utils::N_DEC); globalParams->maxEntries = Utils::String2Int(*ct++, Utils::N_DEC); globalParams->maxBlocks = Utils::String2Int(*ct++, Utils::N_DEC); size_t totalSize = globalParams->blockCount; std::string retryCmd = ""; if (globalParams->env != nullptr && globalParams->env->IsRetry()) { retryCmd = ReloadForRetry(); } size_t initBlock = 0; for (; ct != context.end(); ct++) { std::unique_ptr cmd = std::make_unique(); if (cmd == nullptr) { LOG(ERROR) << "Failed to parse command line."; return false; } if (!cmd->Init(*ct) || cmd->GetCommandType() == CommandType::LAST || globalParams->env == nullptr) { continue; } if (!retryCmd.empty() && globalParams->env->IsRetry()) { if (*ct == retryCmd) { retryCmd.clear(); } if (cmd->GetCommandType() != CommandType::NEW) { LOG(INFO) << "Retry: Command " << *ct << " passed"; continue; } } if (!CommandsExecute(fd, *cmd)) { LOG(ERROR) << "Running command : " << cmd->GetArgumentByPos(0) << " fail"; return false; } if (initBlock == 0) { initBlock = globalParams->written; } if (totalSize != 0 && globalParams->env != nullptr && NeedSetProgress(cmd->GetCommandType())) { globalParams->env->PostMessage("set_progress", std::to_string((static_cast(globalParams->written) - initBlock) / totalSize)); } } return true; } void TransferManager::Init() { globalParams = std::make_unique(); globalParams->writerThreadInfo = std::make_unique(); blocksetMap.clear(); } bool TransferManager::RegisterForRetry(const std::string &cmd) { std::string path = globalParams->retryFile; int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (fd == -1) { LOG(ERROR) << "Failed to create"; return false; } bool ret = Utils::WriteStringToFile(fd, cmd); if (ret == false) { LOG(ERROR) << "Write retry flag error"; } fsync(fd); close(fd); return ret; } std::string TransferManager::ReloadForRetry() const { std::string path = globalParams->retryFile; int fd = open(path.c_str(), O_RDONLY); if (fd < 0) { LOG(ERROR) << "Failed to open"; return ""; } (void)lseek(fd, 0, SEEK_SET); std::string cmd = ""; if (!Utils::ReadFileToString(fd, cmd)) { LOG(ERROR) << "Error to read retry flag"; } close(fd); return cmd; } bool TransferManager::NeedSetProgress(const CommandType &type) { return type == CommandType::NEW || type == CommandType::IMGDIFF || type == CommandType::BSDIFF || type == CommandType::ZERO; } bool TransferManager::CheckResult(const CommandResult result, const std::string &cmd, const CommandType &type) { switch (result) { case SUCCESS: if (type != CommandType::NEW) { RegisterForRetry(cmd); } break; case NEED_RETRY: LOG(INFO) << "Running command need retry!"; if (globalParams->env != nullptr) { globalParams->env->PostMessage("retry_update", cmd); } return false; case FAILED: default: LOG(ERROR) << "Running command failed"; return false; } return true; } } // namespace Updater