/* * Copyright (c) 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 "bin_flow_update.h" #include #include #include "log.h" #include "scope_guard.h" #include "pkg_manager/pkg_stream.h" #include "pkg_package/pkg_pkgfile.h" #include "securec.h" #include "utils.h" namespace Updater { using namespace Uscript; using namespace Hpackage; using namespace std::placeholders; constexpr const char *UPDATE_BIN_FILE = "update.bin"; constexpr uint32_t DEFAULT_SIZE = 4 * 1024 * 1024; BinFlowUpdate::BinFlowUpdate(uint32_t maxBufSize) { maxBufSize_ = maxBufSize == 0 ? DEFAULT_SIZE : maxBufSize; buffer_ = new uint8_t[maxBufSize_]; updateBinProcess_.emplace(BIN_UPDATE_STEP_PRE, [this](uint8_t *data, uint32_t &len) { return this->BinUpdatePreWrite(data, len); }); updateBinProcess_.emplace(BIN_UPDATE_STEP_DO, [this](uint8_t *data, uint32_t &len) { return this->BinUpdateDoWrite(data, len); }); updateBinProcess_.emplace(BIN_UPDATE_STEP_POST, [this](uint8_t *data, uint32_t &len) { return this->BinUpdatePostWrite(data, len); }); pkgManager_ = PkgManager::CreatePackageInstance(); } BinFlowUpdate::~BinFlowUpdate() { PkgManager::ReleasePackageInstance(pkgManager_); if (buffer_ != nullptr) { delete[] buffer_; buffer_ = nullptr; } } int32_t BinFlowUpdate::StartBinFlowUpdate(uint8_t *data, uint32_t len) { if (data == nullptr || len == 0 || pkgManager_ == nullptr) { LOG(ERROR) << "para error"; return -1; } uint32_t remainLen = len; while (remainLen > 0) { // 1: add remained data if (!AddRemainData(data + len - remainLen, remainLen)) { LOG(ERROR) << "AddRemainData error"; return -1; } // 2: parse head if (!headInit_ && UpdateBinHead(buffer_, curlen_) != 0) { LOG(ERROR) << "ParseHead error"; return -1; } // 3: process data updateInfo_.needNewData = false; while (curlen_ > 0 && !updateInfo_.needNewData) { if (auto ret = UpdateBinData(buffer_, curlen_); ret != 0) { LOG(ERROR) << "ProcessData error"; return ret; } } } return 0; } bool BinFlowUpdate::AddRemainData(uint8_t *data, uint32_t &len) { uint32_t copySize = std::min(static_cast(len), static_cast(maxBufSize_ - curlen_)); if (memcpy_s(buffer_ + curlen_, maxBufSize_, data, copySize) != EOK) { LOG(ERROR) << "AddRemainData memcpy failed" << " : " << strerror(errno); return false; } curlen_ += copySize; len -= copySize; return true; } uint32_t BinFlowUpdate::UpdateBinHead(uint8_t *data, uint32_t &len) { PkgManager::StreamPtr stream = nullptr; PkgBuffer buffer(data, len); if (auto ret = pkgManager_->CreatePkgStream(stream, UPDATE_BIN_FILE, buffer); ret != PKG_SUCCESS) { LOG(ERROR) << "ParseHead failed"; return -1; } if (auto ret = pkgManager_->LoadPackageWithStream(UPDATE_BIN_FILE, Utils::GetCertName(), updateInfo_.componentNames, PkgFile::PKG_TYPE_UPGRADE, stream); ret != PKG_SUCCESS) { LOG(ERROR) << "LoadPackage fail ret :"<< ret; return ret; } const PkgInfo *pkgInfo = pkgManager_->GetPackageInfo(UPDATE_BIN_FILE); if (pkgInfo == nullptr || pkgInfo->updateFileHeadLen == 0 || len < pkgInfo->updateFileHeadLen) { LOG(ERROR) << "GetPackageInfo failed"; return -1; } if (len > pkgInfo->updateFileHeadLen && memmove_s(data, len, data + pkgInfo->updateFileHeadLen, len - pkgInfo->updateFileHeadLen) != EOK) { LOG(ERROR) << "memmove failed"; return -1; } len -= pkgInfo->updateFileHeadLen; headInit_ = true; return 0; } std::unique_ptr BinFlowUpdate::GetDataWriter(const std::string &partition) { static std::string lastPartition {}; static int lastIndex = 0; if (lastPartition == partition) { lastIndex++; lastPartition = partition + std::to_string(lastIndex); } else { lastPartition = partition; lastIndex = 0; } const std::string writePath = "/data/updater" + lastPartition; FILE *pFile = fopen(writePath.c_str(), "w+"); if (pFile != nullptr) { uint8_t data[1] {}; fwrite(data, 1, sizeof(data), pFile); fclose(pFile); } LOG(INFO) << "GetDataWriter writePath " << writePath.c_str(); return DataWriter::CreateDataWriter(WRITE_RAW, writePath, static_cast(0)); } int BinFlowUpdate::BinUpdatePreWrite(uint8_t *data, uint32_t &len) { if (procCompIndex_ >= updateInfo_.componentNames.size()) { LOG(ERROR) << "PreWriteBin index error cur:" << procCompIndex_ << " max:" << updateInfo_.componentNames.size(); return -1; } LOG(INFO) << "PreWriteBin name "<< updateInfo_.componentNames[procCompIndex_]; updateInfo_.imageWriteLen = 0; updateInfo_.writer = GetDataWriter(updateInfo_.componentNames[procCompIndex_]); if (updateInfo_.writer == nullptr) { LOG(ERROR) << "GetDataWriter error"; return -1; } updateInfo_.info = pkgManager_->GetFileInfo(updateInfo_.componentNames[procCompIndex_]); if (updateInfo_.info == nullptr) { LOG(ERROR) << ("Can not get file info"); return -1; } updateInfo_.updateStep = BIN_UPDATE_STEP_DO; return 0; } int BinFlowUpdate::BinUpdateDoWrite(uint8_t *data, uint32_t &len) { size_t writeLen = std::min(static_cast(updateInfo_.info->unpackedSize - updateInfo_.imageWriteLen), static_cast(len)); LOG(INFO) << "DoWriteBin len " << len << " unpackedSize " << updateInfo_.info->unpackedSize << " already write " << updateInfo_.imageWriteLen; if (!updateInfo_.writer->Write(data, writeLen, nullptr)) { LOG(ERROR) << "Write failed"; return -1; } if (memmove_s(data, len, data + writeLen, len - writeLen) != EOK) { LOG(ERROR) << "memmove failed"; return -1; } updateInfo_.imageWriteLen += writeLen; len -= writeLen; if (updateInfo_.imageWriteLen == updateInfo_.info->unpackedSize) { LOG(INFO) << "DoWriteBin all len " << updateInfo_.imageWriteLen; updateInfo_.updateStep = BIN_UPDATE_STEP_POST; } else if (updateInfo_.imageWriteLen > updateInfo_.info->unpackedSize) { LOG(INFO) << "DoWriteBin write len " << updateInfo_.imageWriteLen << " all len " << updateInfo_.info->unpackedSize; return -1; } return 0; } int BinFlowUpdate::BinUpdatePostWrite(uint8_t *data, uint32_t &len) { procCompIndex_++; updateInfo_.updateStep = BIN_UPDATE_STEP_PRE; return 0; } int BinFlowUpdate::UpdateBinData(uint8_t *data, uint32_t &len) { auto it = updateBinProcess_.find(updateInfo_.updateStep); if (it == updateBinProcess_.end() || it->second == nullptr) { LOG(ERROR) << "cannot find " << updateInfo_.updateStep; return -1; } return it->second(data, len); } } // Updater