diff --git a/BUILD.gn b/BUILD.gn index 3efa57070ade172f645e0b5bd6754f99e4bc3a1e..e563859bd987cc84753f7a034c41e4a8cc28a4c6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -49,6 +49,7 @@ group("unittest") { "test/unittest/flow_update/update_bin:bin_flow_update_test", "test/unittest/package:package_unittest", "test/unittest/script:script_unittest", + "test/unittest/stream_update:bin_chunk_update_test", "test/unittest/updater_binary:binary_unittest", "test/unittest/utils:utils_test", ] diff --git a/bundle.json b/bundle.json index 132f646a592ccaf6c0924d90b21a53be9bb5a8e5..c997c816dd39918f0c3e2756e3a5d6bfa0b07e50 100644 --- a/bundle.json +++ b/bundle.json @@ -86,7 +86,8 @@ "//base/update/updater/services/diffpatch/diff:libdiff", "//base/update/updater/services/diffpatch:diff(//build/toolchain/linux:clang_${host_cpu})", "//base/update/updater/services/ui:libui", - "//base/update/updater/services/flow_update/update_bin:libBinFlowUpdate" + "//base/update/updater/services/flow_update/update_bin:libBinFlowUpdate", + "//base/update/updater/services/stream_update:libbinchunkupdate" ], "inner_kits": [ { @@ -305,6 +306,13 @@ "header_base": "//base/update/updater/services/flow_update/update_bin" } }, + { + "name": "//base/update/updater/services/stream_update:libbinchunkupdate", + "header": { + "header_files": [], + "header_base": "//base/update/updater/services/stream_update" + } + }, { "name": "//base/update/updater/interfaces/kits/slot_info:libslotinfo", "header": { diff --git a/interfaces/kits/include/slot_info/slot_info.h b/interfaces/kits/include/slot_info/slot_info.h index 3264de1ffd995d7cd708c4563d0b59f01da5ef54..fa92c546da47f78d3b455f51345fc1fb0b801570 100644 --- a/interfaces/kits/include/slot_info/slot_info.h +++ b/interfaces/kits/include/slot_info/slot_info.h @@ -22,6 +22,7 @@ namespace Updater { void GetPartitionSuffix(std::string &suffix); +void GetActivePartitionSuffix(std::string &suffix); void SetActiveSlot(); } // Updater #endif /* SLOT_INFO_H */ diff --git a/interfaces/kits/slot_info/slot_info.cpp b/interfaces/kits/slot_info/slot_info.cpp index c72c49c428126fe4e74f8d1edaec591a1a2df2ef..e6f2787dcd01ac11f55d9d30b7cadbf5ab21eb1f 100644 --- a/interfaces/kits/slot_info/slot_info.cpp +++ b/interfaces/kits/slot_info/slot_info.cpp @@ -26,6 +26,10 @@ void GetPartitionSuffix(std::string &suffix) { suffix = ""; } +void GetActivePartitionSuffix(std::string &suffix) +{ + suffix = ""; +} void SetActiveSlot() { } @@ -50,6 +54,25 @@ void GetPartitionSuffix(std::string &suffix) } } +void GetActivePartitionSuffix(std::string &suffix) +{ + OHOS::HDI::Partitionslot::V1_0::PartitionSlotManager psMgr; + int32_t curSlot = -1; + int32_t numOfSlots = 0; + int32_t ret = psMgr.GetCurrentSlot(curSlot, numOfSlots); + LOG(INFO) << "Get slot info, curSlot: " << curSlot << "numOfSlots :" << numOfSlots; + if (ret != 0 || curSlot <= 0 || curSlot > 2 || numOfSlots != 2) { // 2: max slot num + suffix = ""; + return; + } + + ret = psMgr.GetSlotSuffix(curSlot, suffix); + if (ret != 0) { + LOG(ERROR) << "Get slot suffix error, partitionPath: " << suffix; + suffix = ""; + } +} + void SetActiveSlot() { OHOS::HDI::Partitionslot::V1_0::PartitionSlotManager psMgr; diff --git a/services/applypatch/block_set.cpp b/services/applypatch/block_set.cpp index 2573a919607e2b0b11c907121c4148aec35d8a5e..0b0cddee5c275e8b13288e2315581aafca0b3012 100644 --- a/services/applypatch/block_set.cpp +++ b/services/applypatch/block_set.cpp @@ -258,9 +258,11 @@ int32_t BlockSet::LoadSourceBuffer(const Command &cmd, size_t &pos, std::vector< if (targetCmd != "-") { BlockSet srcBlk; srcBlk.ParserAndInsert(targetCmd); - isOverlap = IsTwoBlocksOverlap(srcBlk, *this); + if (!cmd.IsStreamCmd()) { + isOverlap = IsTwoBlocksOverlap(srcBlk, *this); + } // read source data - if (srcBlk.ReadDataFromBlock(cmd.GetFileDescriptor(), sourceBuffer) == 0) { + if (srcBlk.ReadDataFromBlock(cmd.GetSrcFileDescriptor(), sourceBuffer) == 0) { LOG(ERROR) << "ReadDataFromBlock failed"; return -1; } @@ -308,8 +310,13 @@ int32_t BlockSet::LoadTargetBuffer(const Command &cmd, std::vector &buf bool isOverlap = false; auto ret = LoadSourceBuffer(cmd, pos, buffer, isOverlap, blockSize); if (ret != 1) { + LOG(ERROR) << "LoadSourceBuffer failed"; return ret; } + if (cmd.IsStreamCmd()) { + return 0; + } + std::string storeBase = cmd.GetTransferParams()->storeBase; std::string storePath = storeBase + "/" + srcHash; struct stat storeStat {}; @@ -389,7 +396,7 @@ int32_t BlockSet::WriteDiffToBlock(const Command &cmd, std::vector &sou if (isImgDiff) { std::vector empty; UpdatePatch::PatchParam patchParam = {sourceBuffer.data(), srcBuffSize, patchBuffer, patchLength}; - std::unique_ptr writer = std::make_unique(cmd.GetFileDescriptor(), *this); + std::unique_ptr writer = std::make_unique(cmd.GetTargetFileDescriptor(), *this); if (writer.get() == nullptr) { LOG(ERROR) << "Cannot create block writer, pkgdiff patch abort!"; return -1; @@ -406,7 +413,7 @@ int32_t BlockSet::WriteDiffToBlock(const Command &cmd, std::vector &sou } else { LOG(DEBUG) << "Run bsdiff patch."; UpdatePatch::PatchBuffer patchInfo = {patchBuffer, 0, patchLength}; - std::unique_ptr writer = std::make_unique(cmd.GetFileDescriptor(), *this); + std::unique_ptr writer = std::make_unique(cmd.GetTargetFileDescriptor(), *this); if (writer.get() == nullptr) { LOG(ERROR) << "Cannot create block writer, pkgdiff patch abort!"; return -1; @@ -421,7 +428,7 @@ int32_t BlockSet::WriteDiffToBlock(const Command &cmd, std::vector &sou return -1; } } - if (fsync(cmd.GetFileDescriptor()) == -1) { + if (fsync(cmd.GetTargetFileDescriptor()) == -1) { LOG(ERROR) << "Failed to sync restored data"; return -1; } diff --git a/services/applypatch/command.cpp b/services/applypatch/command.cpp index afa21ec87aa6d459d4fd2ff4d77e016604a27529..0e4f11af5292e302097683d0db68d1898f29a54e 100644 --- a/services/applypatch/command.cpp +++ b/services/applypatch/command.cpp @@ -33,7 +33,8 @@ bool Command::Init(const std::string &cmdLine) Command::~Command() { - fd_.reset(); + srcFd_.reset(); + targetFd_.reset(); } CommandType Command::GetCommandType() const @@ -59,14 +60,34 @@ std::string Command::GetCommandLine() const return cmdLine_; } -void Command::SetFileDescriptor(int fd) +void Command::SetSrcFileDescriptor(int fd) { - fd_ = std::make_unique(fd); + srcFd_ = std::make_unique(fd); } -int Command::GetFileDescriptor() const +int Command::GetSrcFileDescriptor() const { - return *fd_; + return *srcFd_; +} + +void Command::SetTargetFileDescriptor(int fd) +{ + targetFd_ = std::make_unique(fd); +} + +int Command::GetTargetFileDescriptor() const +{ + return *targetFd_; +} + +void Command::SetIsStreamCmd(bool isStreamCmd) +{ + isStreamCmd_ = isStreamCmd; +} + +bool Command::IsStreamCmd() const +{ + return isStreamCmd_; } TransferParams* Command::GetTransferParams() const @@ -94,6 +115,8 @@ CommandType Command::ParseCommandType(const std::string &firstCmd) return CommandType::STASH; } else if (firstCmd == "zero") { return CommandType::ZERO; + } else if (firstCmd == "copy") { + return CommandType::COPY; } return CommandType::LAST; } diff --git a/services/applypatch/command_function.cpp b/services/applypatch/command_function.cpp index 374d17a50b2a4631de94849cb39786902d467d9d..47af4424560026ce033e411ccc533e5cf09c6018 100644 --- a/services/applypatch/command_function.cpp +++ b/services/applypatch/command_function.cpp @@ -28,7 +28,8 @@ extern "C" __attribute__((constructor)) void RegistBlockUpdateCommandFunction(vo { "erase", []() { return std::make_unique(); } }, { "free", []() { return std::make_unique(); } }, { "move", []() { return std::make_unique(); } }, - { "stash", []() { return std::make_unique(); } } + { "stash", []() { return std::make_unique(); } }, + { "copy", []() { return std::make_unique(); } } }; for (auto &iter : COMMANDFUNC) { CommandFunctionFactory::GetInstance().RegistCommandFunction(iter.first, iter.second()); diff --git a/services/applypatch/command_process.cpp b/services/applypatch/command_process.cpp index a7257438ae2ec8f8d7c9f00776cdab03f2a4dc94..39569b3b0045b68cf3250fbd2cc671503473ee99 100644 --- a/services/applypatch/command_process.cpp +++ b/services/applypatch/command_process.cpp @@ -42,12 +42,16 @@ CommandResult AbortCommandFn::Execute(const Command ¶ms) CommandResult NewCommandFn::Execute(const Command ¶ms) { + if (params.IsStreamCmd()) { + return (StreamExecute(params) != 0) ? FAILED : SUCCESS; + } BlockSet bs; - bs.ParserAndInsert(params.GetArgumentByPos(1)); + size_t pos = H_NEW_CMD_ARGS_START; + bs.ParserAndInsert(params.GetArgumentByPos(pos)); LOG(INFO) << " writing " << bs.TotalBlockSize() << " blocks of new data"; auto writerThreadInfo = params.GetTransferParams()->writerThreadInfo.get(); pthread_mutex_lock(&writerThreadInfo->mutex); - writerThreadInfo->writer = std::make_unique(params.GetFileDescriptor(), bs); + writerThreadInfo->writer = std::make_unique(params.GetTargetFileDescriptor(), bs); pthread_cond_broadcast(&writerThreadInfo->cond); while (writerThreadInfo->writer != nullptr) { LOG(DEBUG) << "wait for new data write done..."; @@ -69,6 +73,46 @@ CommandResult NewCommandFn::Execute(const Command ¶ms) return SUCCESS; } +int32_t NewCommandFn::StreamExecute(const Command ¶ms) +{ + size_t pos = H_NEW_CMD_ARGS_START; + uint8_t *addr = params.GetTransferParams()->dataBuffer; + size_t size = params.GetTransferParams()->dataBufferSize; + std::string tgtHash = ""; + tgtHash = params.GetArgumentByPos(pos++); + LOG(INFO) << "StreamExecute size:" << size << " cmd:" << params.GetCommandLine(); + BlockSet bs; + bs.ParserAndInsert(params.GetArgumentByPos(pos++)); + std::unique_ptr writer = std::make_unique(params.GetTargetFileDescriptor(), bs); + while (size > 0) { + size_t toWrite = std::min(size, writer->GetBlocksSize() - writer->GetTotalWritten()); + LOG(INFO) << "StreamExecute toWrite:" << toWrite; + // No more data to write. + if (toWrite == 0) { + break; + } + bool ret = writer->Write(addr, toWrite, nullptr); + if (!ret) { + return -1; + } + size -= toWrite; + addr += toWrite; + } + size_t tgtBlockSize = bs.TotalBlockSize() * H_BLOCK_SIZE; + std::vector tgtBuffer(tgtBlockSize); + + if (bs.ReadDataFromBlock(params.GetTargetFileDescriptor(), tgtBuffer) == 0) { + LOG(ERROR) << "Read data from block error, TotalBlockSize: " << bs.TotalBlockSize(); + return -1; + } + if (bs.VerifySha256(tgtBuffer, bs.TotalBlockSize(), tgtHash) == 0) { + LOG(ERROR) << "Will write same sha256 blocks to target, no need to write"; + return -1; + } + std::vector().swap(tgtBuffer); + return 0; +} + CommandResult ZeroAndEraseCommandFn::Execute(const Command ¶ms) { bool isErase = false; @@ -78,7 +122,7 @@ CommandResult ZeroAndEraseCommandFn::Execute(const Command ¶ms) } if (isErase) { struct stat statBlock {}; - if (fstat(params.GetFileDescriptor(), &statBlock) == -1) { + if (fstat(params.GetTargetFileDescriptor(), &statBlock) == -1) { LOG(ERROR) << "Failed to fstat"; return FAILED; } @@ -93,7 +137,7 @@ CommandResult ZeroAndEraseCommandFn::Execute(const Command ¶ms) BlockSet blk; blk.ParserAndInsert(params.GetArgumentByPos(1)); LOG(INFO) << "Parser params to block set"; - auto ret = CommandResult(blk.WriteZeroToBlock(params.GetFileDescriptor(), isErase)); + auto ret = CommandResult(blk.WriteZeroToBlock(params.GetTargetFileDescriptor(), isErase)); if (ret == SUCCESS && !isErase) { params.GetTransferParams()->written += blk.TotalBlockSize(); } @@ -104,29 +148,35 @@ bool LoadTarget(const Command ¶ms, size_t &pos, std::vector &buffer BlockSet &targetBlock, CommandResult &result) { CommandType type = params.GetCommandType(); + std::string srcHash = ""; + std::string tgtHash = ""; // Read sha256 of source and target - std::string srcHash = params.GetArgumentByPos(pos++); - std::string tgtHash = srcHash; - if (type != CommandType::MOVE) { + if (type == CommandType::BSDIFF || type == CommandType::IMGDIFF) { + srcHash = params.GetArgumentByPos(pos++); tgtHash = params.GetArgumentByPos(pos++); + } else if (type == CommandType::MOVE) { + srcHash = params.GetArgumentByPos(pos++); + tgtHash = srcHash; } // Read the target's buffer to determine whether it needs to be written std::string cmdTmp = params.GetArgumentByPos(pos++); targetBlock.ParserAndInsert(cmdTmp); - size_t tgtBlockSize = targetBlock.TotalBlockSize() * H_BLOCK_SIZE; - std::vector tgtBuffer(tgtBlockSize); + if (type != CommandType::COPY) { + size_t tgtBlockSize = targetBlock.TotalBlockSize() * H_BLOCK_SIZE; + std::vector tgtBuffer(tgtBlockSize); - if (targetBlock.ReadDataFromBlock(params.GetFileDescriptor(), tgtBuffer) == 0) { - LOG(ERROR) << "Read data from block error, TotalBlockSize: " << targetBlock.TotalBlockSize(); - result = FAILED; - return false; - } - if (targetBlock.VerifySha256(tgtBuffer, targetBlock.TotalBlockSize(), tgtHash) == 0) { - result = SUCCESS; - return false; + if (targetBlock.ReadDataFromBlock(params.GetTargetFileDescriptor(), tgtBuffer) == 0) { + LOG(ERROR) << "Read data from block error, TotalBlockSize: " << targetBlock.TotalBlockSize(); + result = FAILED; + return false; + } + if (targetBlock.VerifySha256(tgtBuffer, targetBlock.TotalBlockSize(), tgtHash) == 0) { + result = SUCCESS; + return false; + } + std::vector().swap(tgtBuffer); } - std::vector().swap(tgtBuffer); std::string blockLen = params.GetArgumentByPos(pos++); size_t srcBlockSize = String2Int(blockLen, N_DEC); buffer.resize(srcBlockSize * H_BLOCK_SIZE); @@ -152,6 +202,8 @@ CommandResult DiffAndMoveCommandFn::Execute(const Command ¶ms) size_t pos = H_DIFF_CMD_ARGS_START; if (type == CommandType::MOVE) { pos = H_MOVE_CMD_ARGS_START; + } else if (type == CommandType::COPY) { + pos = H_COPY_CMD_ARGS_START; } BlockSet targetBlock; @@ -165,14 +217,20 @@ CommandResult DiffAndMoveCommandFn::Execute(const Command ¶ms) } int32_t ret = -1; - if (type != CommandType::MOVE) { + if (type != CommandType::MOVE && type != CommandType::COPY) { pos = H_MOVE_CMD_ARGS_START; - size_t offset = Utils::String2Int(params.GetArgumentByPos(pos++), Utils::N_DEC); + size_t offset; + if (params.IsStreamCmd()) { + offset = 0; + pos++; + } else { + offset = Utils::String2Int(params.GetArgumentByPos(pos++), Utils::N_DEC); + } size_t patchLength = Utils::String2Int(params.GetArgumentByPos(pos++), Utils::N_DEC); - uint8_t *patchBuffer = params.GetTransferParams()->patchDataBuffer + offset; + uint8_t *patchBuffer = params.GetTransferParams()->dataBuffer + offset; ret = WriteDiffToBlock(params, buffer, patchBuffer, patchLength, targetBlock); } else { - ret = targetBlock.WriteDataToBlock(params.GetFileDescriptor(), buffer) == 0 ? -1 : 0; + ret = targetBlock.WriteDataToBlock(params.GetTargetFileDescriptor(), buffer) == 0 ? -1 : 0; } if (ret != 0) { LOG(ERROR) << "fail to write block data."; @@ -217,7 +275,7 @@ CommandResult StashCommandFn::Execute(const Command ¶ms) return SUCCESS; } LOG(DEBUG) << "Read block data to buffer"; - if (srcBlk.ReadDataFromBlock(params.GetFileDescriptor(), buffer) == 0) { + if (srcBlk.ReadDataFromBlock(params.GetSrcFileDescriptor(), buffer) == 0) { LOG(ERROR) << "Error to load block data"; return FAILED; } diff --git a/services/applypatch/command_process.h b/services/applypatch/command_process.h index 4863a909798cb95275af83367c58cf2a75cdfa26..42f554b9edb07c4beb44976c599369e119c75df5 100644 --- a/services/applypatch/command_process.h +++ b/services/applypatch/command_process.h @@ -31,6 +31,8 @@ public: NewCommandFn() {} ~NewCommandFn() override {} CommandResult Execute(const Command ¶ms) override; +private: + int32_t StreamExecute(const Command ¶ms); }; class ZeroAndEraseCommandFn : public CommandFunction { diff --git a/services/applypatch/transfer_manager.cpp b/services/applypatch/transfer_manager.cpp index d22cf1358500f0710b135cc0e64dad714a7cdc2c..ddbc3e660033f59bdfbc23d66ed00e30a3809a1b 100644 --- a/services/applypatch/transfer_manager.cpp +++ b/services/applypatch/transfer_manager.cpp @@ -35,7 +35,8 @@ TransferManager::TransferManager() bool TransferManager::CommandsExecute(int fd, Command &cmd) { - cmd.SetFileDescriptor(fd); + cmd.SetSrcFileDescriptor(fd); + cmd.SetTargetFileDescriptor(fd); CommandFunction* cf = CommandFunctionFactory::GetInstance().GetCommandFunction(cmd.GetCommandHead()); if (cf == nullptr) { LOG(ERROR) << "Failed to get cmd exec"; diff --git a/services/diffpatch/diff/image_diff.cpp b/services/diffpatch/diff/image_diff.cpp index 475a4ebbaa8a2d98e8016e32e8b3d6d4c7874ead..f36ea15b41ad6a4a3b6b454e95533aa3c9dc813f 100644 --- a/services/diffpatch/diff/image_diff.cpp +++ b/services/diffpatch/diff/image_diff.cpp @@ -87,7 +87,7 @@ int32_t ImageDiff::MakePatch(const std::string &patchName) int32_t ImageDiff::SplitImage(const PatchBuffer &oldInfo, const PatchBuffer &newInfo) { - size_t blockCount = newInfo.length / limit_ + 1; + size_t blockCount = (newInfo.length % limit_ == 0) ? (newInfo.length / limit_) : (newInfo.length / limit_ + 1); size_t oldBlockSize = oldInfo.length / blockCount; size_t newBlockSize = newInfo.length / blockCount; int32_t type = (oldInfo.length == 0) ? BLOCK_RAW : BLOCK_NORMAL; diff --git a/services/diffpatch/patch_shared/patch_shared.cpp b/services/diffpatch/patch_shared/patch_shared.cpp index b7ae7468e83cec5456dd334b98163537d7671379..b4df611bc78007f5b8675f062c95c84c36c5c533 100644 --- a/services/diffpatch/patch_shared/patch_shared.cpp +++ b/services/diffpatch/patch_shared/patch_shared.cpp @@ -398,7 +398,7 @@ static int32_t ExecuteUpdateBlock(Uscript::UScriptEnv &env, const UpdateBlockInf env.GetPkgManager()->ClosePkgStream(outStream); if (ExtractFileByNameFunc(env, infos.patchDataName, outStream, - transferParams->patchDataBuffer, transferParams->patchDataSize) != USCRIPT_SUCCESS) { + transferParams->dataBuffer, transferParams->dataBufferSize) != USCRIPT_SUCCESS) { return USCRIPT_ERROR_EXECUTE; } diff --git a/services/include/applypatch/block_set.h b/services/include/applypatch/block_set.h index 8c9d87c2473a74d4e7d9f418dc00bf0e84bf0944..c4b1861403d3ef096639015abec3a8892b320d65 100644 --- a/services/include/applypatch/block_set.h +++ b/services/include/applypatch/block_set.h @@ -25,8 +25,10 @@ using BlockPair = std::pair; static constexpr int H_BLOCK_SIZE = 4096; static constexpr int H_CMD_ARGS_LIMIT = 2; +static constexpr int H_NEW_CMD_ARGS_START = 1; static constexpr int H_DIFF_CMD_ARGS_START = 3; static constexpr int H_MOVE_CMD_ARGS_START = 1; +static constexpr int H_COPY_CMD_ARGS_START = 1; static constexpr int H_ZERO_NUMBER = 0; diff --git a/services/include/applypatch/command.h b/services/include/applypatch/command.h index 9663b20caac52f224de4feb36cdde229414017c6..24d33f15b37ee808bf83f32e5673ceb9ee7c3b37 100644 --- a/services/include/applypatch/command.h +++ b/services/include/applypatch/command.h @@ -36,11 +36,17 @@ public: virtual bool Init(const std::string &cmd_line); CommandType GetCommandType() const; std::string GetArgumentByPos(size_t pos) const; - void SetFileDescriptor(int fd); - int GetFileDescriptor() const; + void SetSrcFileDescriptor(int fd); + int GetSrcFileDescriptor() const; + void SetTargetFileDescriptor(int fd); + int GetTargetFileDescriptor() const; + TransferParams* GetTransferParams() const; std::string GetCommandLine() const; std::string GetCommandHead() const; + void SetIsStreamCmd(bool isStreamCmd); + bool IsStreamCmd() const; + private: CommandType ParseCommandType(const std::string &first_cmd); @@ -48,8 +54,10 @@ private: std::string cmdhead_ {}; std::string cmdLine_ {}; std::vector tokens_ {}; - std::unique_ptr fd_ {}; + std::unique_ptr srcFd_ {}; + std::unique_ptr targetFd_ {}; TransferParams* transferParams_; + bool isStreamCmd_ {false}; }; } // namespace Updater #endif diff --git a/services/include/applypatch/command_const.h b/services/include/applypatch/command_const.h index 30e75ffeb353852da0b4243e290961be8e4186cf..810093dfb5866c04859767491c0d146694630bd8 100644 --- a/services/include/applypatch/command_const.h +++ b/services/include/applypatch/command_const.h @@ -25,6 +25,7 @@ enum CommandType { NEW, STASH, ZERO, + COPY, LAST, }; diff --git a/services/include/applypatch/transfer_manager.h b/services/include/applypatch/transfer_manager.h index a13d3e7c62880db921ef625812b247b3451d7b9d..d67bf800c213ad3437baae11a4a31421d85492ae 100644 --- a/services/include/applypatch/transfer_manager.h +++ b/services/include/applypatch/transfer_manager.h @@ -52,8 +52,8 @@ struct TransferParams { std::string freeStash; std::string retryFile; std::string devPath; - uint8_t *patchDataBuffer; - size_t patchDataSize; + uint8_t *dataBuffer; + size_t dataBufferSize; bool canWrite; }; diff --git a/services/stream_update/BUILD.gn b/services/stream_update/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..aabb09961f850b2fd95cc964fce86269ab434b37 --- /dev/null +++ b/services/stream_update/BUILD.gn @@ -0,0 +1,64 @@ +# Copyright (c) 2025 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. + +import("//base/update/updater/updater_default_cfg.gni") +import("//build/ohos.gni") + +updater_path = rebase_path("${updater_absolutely_path}", ".") + +config("libstreamupdate_exported_headers") { + visibility = [ ":*" ] + include_dirs = [ + "${updater_path}/services/stream_update", + "${updater_path}/services", + "${updater_path}/services/common", + "${updater_path}/services/include", + "${updater_path}/services/include/applypatch", + "${updater_path}/services/include/log", + "${updater_path}/services/include/package", + "${updater_path}/services/include/script", + "${updater_path}/services/package", + "${updater_path}/services/package/pkg_algorithm", + "${updater_path}/services/package/pkg_manager", + "${updater_path}/services/package/pkg_package", + "${updater_path}/services/script", + ] +} + +ohos_static_library("libbinchunkupdate") { + sources = [ "bin_chunk_update.cpp" ] + + include_dirs = [ + "${updater_path}/interfaces/kits/include", + "${updater_path}/utils/include", + ] + deps = [ + "${updater_path}/interfaces/kits/packages:libpackageExt", + "${updater_path}/services/applypatch:libapplypatch", + "${updater_path}/services/fs_manager:libfsmanager", + "${updater_path}/services/log:libupdaterlog", + "${updater_path}/services/package:libupdaterpackage", + "${updater_path}/utils:libutils", + ] + external_deps = [ + "bounds_checking_function:libsec_static", + "init:libbegetutil_static", + "init:libfsmanager_static_real", + "openssl:libcrypto_static", + ] + + public_configs = [ ":libstreamupdate_exported_headers" ] + + subsystem_name = "updater" + part_name = "updater" +} diff --git a/services/stream_update/bin_chunk_update.cpp b/services/stream_update/bin_chunk_update.cpp new file mode 100755 index 0000000000000000000000000000000000000000..5a7736e9ca50d9fc3834b6ddafd1a0f03feeb606 --- /dev/null +++ b/services/stream_update/bin_chunk_update.cpp @@ -0,0 +1,815 @@ +/* + * Copyright (c) 2025 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_chunk_update.h" + +#include +#include +#include +#include // 用于 std::setw 和 std::setfill +#include +#include // 用于 std::ostringstream +#include + +#include "applypatch/command_process.h" +#include "applypatch/store.h" +#include "fs_manager/mount.h" +#include "log.h" +#include "scope_guard.h" +#include "slot_info/slot_info.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 const size_t HASH_BUFFER_SIZE = 50 * 1024; +BinChunkUpdate::BinChunkUpdate(uint32_t maxBufSize) +{ + LOG(DEBUG) << "BinChunkUpdate::BinChunkUpdate enter"; + maxBufSize_ = maxBufSize; + buffer_ = new uint8_t[maxBufSize_]; + chunkInstallProcess_.emplace(CHUNK_INSTALL_STEP_PRE, [this](uint8_t *data, uint32_t &len) { + return this->ChunkInstallPreWrite(data, len); + }); + chunkInstallProcess_.emplace(CHUNK_INSTALL_STEP_DO, [this](uint8_t *data, uint32_t &len) { + return this->ChunkInstallDoWrite(data, len); + }); + chunkInstallProcess_.emplace(CHUNK_INSTALL_STEP_POST, [this](uint8_t *data, uint32_t &len) { + return this->ChunkInstallPostWrite(data, len); + }); + pkgManager_ = PkgManager::CreatePackageInstance(); +} + +BinChunkUpdate::~BinChunkUpdate() +{ + PkgManager::ReleasePackageInstance(pkgManager_); + if (buffer_ != nullptr) { + delete[] buffer_; + buffer_ = nullptr; + } +} + +UpdateResultCode BinChunkUpdate::StartBinChunkUpdate(const uint8_t *data, uint32_t len, uint32_t &dealLen) +{ + LOG(DEBUG) << "BinChunkUpdate::StartBinChunkUpdate enter"; + UpdateResultCode ret = STREAM_UPDATE_SUCCESS; + if (data == nullptr || len == 0 || pkgManager_ == nullptr) { + LOG(ERROR) << "para error"; + return STREAM_UPDATE_FAILURE; + } + uint32_t remainLen = len; + uint32_t leftLen = curlen_; + LOG(DEBUG) << "BinChunkUpdate::StartBinChunkUpdate leftLen:" << leftLen; + dealLen = 0; + while (remainLen > 0) { + if (!AddRemainData(data + len - remainLen, remainLen)) { + LOG(ERROR) << "AddRemainData error"; + return STREAM_UPDATE_FAILURE; + } + updateInfo_.needNewData = false; + + // 处理缓冲区的数据 + ret = ProcessBufferData(); + if (ret == STREAM_UPDATE_FAILURE) { + return ret; + } + + // 移动剩余数据 + if (!MoveRemainingData()) { + return STREAM_UPDATE_FAILURE; + } + } + + dealLen = len + leftLen - curlen_; + LOG(DEBUG) << "BinChunkUpdate StartBinChunkUpdate dealLen:" << dealLen << " len:" << len << " curlen_:" << curlen_ + << " leftLen:" << leftLen; + return ret; +} + +UpdateResultCode BinChunkUpdate::ProcessBufferData() +{ + UpdateResultCode ret = STREAM_UPDATE_SUCCESS; + while ((curlen_ - offset_) > 0 && !updateInfo_.needNewData) { + LOG(DEBUG) << "BinChunkUpdate::StartBinChunkUpdate curlen_:" << curlen_ << " offset_:" << offset_; + uint16_t type = ReadLE16(buffer_ + offset_); + LOG(DEBUG) << "BinChunkUpdate::StartBinChunkUpdate type:" << type; + + switch (type) { + case BIN_UPDATE_HEAD_TIP: + ret = UpdateBinHead(buffer_, curlen_); + break; + case BIN_UPDATE_DATA_TIP: + ret = UpdateBinData(buffer_, curlen_); + break; + case BIN_UPDATE_HASH_TIP: + ret = UpdateBinHash(buffer_, curlen_); + break; + default: + ret = UpdateBinOther(buffer_, curlen_); + break; + } + + if (ret == STREAM_UPDATE_FAILURE) { + LOG(ERROR) << "Update failed for type: " << type; + return ret; + } + } + + return ret; +} + +bool BinChunkUpdate::MoveRemainingData() +{ + LOG(DEBUG) << "curlen_:" << curlen_ << " offset_:" << offset_; + + if ((curlen_ - offset_) > 0) { + if (memmove_s(buffer_, curlen_, buffer_ + offset_, curlen_ - offset_) != EOK) { + LOG(ERROR) << "memmove failed"; + return false; + } + curlen_ -= offset_; + } else { + if (memset_s(buffer_, maxBufSize_, 0, maxBufSize_) != 0) { + LOG(ERROR) << "memset_s failed"; + return false; + } + curlen_ = 0; + } + + return true; +} + +bool BinChunkUpdate::AddRemainData(const uint8_t *data, uint32_t &len) +{ + if (data == nullptr || len == 0) { + LOG(ERROR) << "AddRemainData para error"; + return false; + } + uint32_t copySize = std::min(static_cast(len), static_cast(maxBufSize_ - curlen_)); + LOG(DEBUG) << "BinChunkUpdate AddRemainData curlen_:" << curlen_ << " copySize:" << copySize; + if (memcpy_s(buffer_ + curlen_, maxBufSize_, data, copySize) != EOK) { + LOG(ERROR) << "AddRemainData memcpy failed" << " : " << strerror(errno); + return false; + } + curlen_ += copySize; + len -= copySize; + offset_ = 0; + return true; +} + +UpdateResultCode BinChunkUpdate::UpdateBinHash(uint8_t *data, uint32_t &len) +{ + LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash enter"; + uint32_t offset = offset_; + PartitionHashInfo hashInfos; + std::vector signData; + std::vector> futures; + + // 初始化 SHA256 算法 + updateInfo_.algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(PKG_DIGEST_TYPE_SHA256); + if (updateInfo_.algorithm == nullptr) { + LOG(ERROR) << "algorithm is null"; + return STREAM_UPDATE_FAILURE; + } + updateInfo_.algorithm->Init(); + + // 读取分区数量 + if (!ProcessPartitionNum(data, len, offset)) { + return STREAM_UPDATE_SUCCESS; + } + + // 读取分区hash数据 + if (!ProcessPartitionData(data, len, offset, hashInfos)) { + return STREAM_UPDATE_SUCCESS; + } + + // 读取签名 + if (!ProcessSignature(data, len, offset, signData)) { + return STREAM_UPDATE_SUCCESS; + } + + offset_ = offset; + + // 签名验证 + if (!VerifySignature(signData)) { + return STREAM_UPDATE_FAILURE; + } + + // 完整性验证(异步处理哈希验证) + if (!VerifyPartitionHashes(hashInfos, futures)) { + return STREAM_UPDATE_FAILURE; + } + + //切换ab分区 + #ifndef UPDATER_UT + SetActiveSlot(); + #else + int result = remove("/data/updater/test.txt"); + if (result != 0) { + LOG(ERROR) << "Failed to remove /data/updater/test.txt, error: " << strerror(errno); + } + #endif + LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash exit"; + return STREAM_UPDATE_COMPLETE; +} + +bool BinChunkUpdate::ProcessPartitionNum(uint8_t *data, uint32_t &len, uint32_t &offset) +{ + PkgTlvHH tlv; + + // 读取TLV头部信息 + if ((len - offset) < sizeof(PkgTlvHH)) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + tlv.type = ReadLE16(data + offset); + LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash tlv.type:" << tlv.type; + tlv.length = ReadLE16(data + offset + sizeof(uint16_t)); + LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash tlv.length:" << tlv.length; + updateInfo_.algorithm->Update({data + offset, sizeof(PkgTlvHH)}, sizeof(PkgTlvHH)); + offset += sizeof(PkgTlvHH); + + // 读取分区数量 + if ((len - offset) < tlv.length) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + updateInfo_.patitionNum = ReadLE16(data + offset); + LOG(INFO) << "BinChunkUpdate::UpdateBinHash patitionNum:" << updateInfo_.patitionNum; + updateInfo_.algorithm->Update({data + offset, tlv.length}, tlv.length); + offset += tlv.length; + + return true; +} + +bool BinChunkUpdate::ProcessPartitionData(uint8_t *data, uint32_t &len, uint32_t &offset, PartitionHashInfo &hashInfos) +{ + PkgTlvHH tlv; + + for (auto i = 0; i < updateInfo_.patitionNum; i++) { + // 读取分区名称 + if ((len - offset) < sizeof(PkgTlvHH)) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + tlv.type = ReadLE16(data + offset); + tlv.length = ReadLE16(data + offset + sizeof(uint16_t)); + updateInfo_.algorithm->Update({data + offset, sizeof(PkgTlvHH)}, sizeof(PkgTlvHH)); + offset += sizeof(PkgTlvHH); + + std::string patition; + PkgFileImpl::ConvertBufferToString(patition, {data + offset, tlv.length}); + LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash patition:" << patition; + updateInfo_.algorithm->Update({data + offset, tlv.length}, tlv.length); + offset += tlv.length; + + // 读取哈希值 + std::string hashBuf; + if (!ReadHash(data, len, offset, hashBuf)) { + return false; + } + + hashInfos.hashValues[patition] = hashBuf; + + // 读取数据长度 + if (!ReadDataLength(data, len, offset, patition, hashInfos.dataLenInfos)) { + return false; + } + } + + return true; +} + +bool BinChunkUpdate::ProcessSignature(uint8_t *data, uint32_t &len, uint32_t &offset, + std::vector &signData) +{ + PkgTlvHI tlv2; + + if ((len - offset) < sizeof(PkgTlvHI)) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + tlv2.type = ReadLE16(data + offset); + LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash tlv2.type:" << tlv2.type; + tlv2.length = ReadLE32(data + offset + sizeof(uint16_t)); + LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash tlv2.length:" << tlv2.length; + offset += sizeof(PkgTlvHI); + if ((len - offset) < tlv2.length) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + signData.assign(data + offset, data + offset + tlv2.length); + offset += tlv2.length; + + return true; +} + +bool BinChunkUpdate::ReadHash(uint8_t *data, uint32_t &len, uint32_t &offset, std::string &hashBuf) +{ + PkgTlvHH tlv; + + if ((len - offset) < sizeof(PkgTlvHH)) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + tlv.type = ReadLE16(data + offset); + tlv.length = ReadLE16(data + offset + sizeof(uint16_t)); + updateInfo_.algorithm->Update({data + offset, sizeof(PkgTlvHH)}, sizeof(PkgTlvHH)); + offset += sizeof(PkgTlvHH); + + if ((len - offset) < tlv.length) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + PkgFileImpl::ConvertBufferToString(hashBuf, {data + offset, tlv.length}); + updateInfo_.algorithm->Update({data + offset, tlv.length}, tlv.length); + offset += tlv.length; + + return true; +} + +bool BinChunkUpdate::ReadDataLength(uint8_t *data, uint32_t &len, uint32_t &offset, + const std::string &patition, std::map &dataLenInfos) +{ + PkgTlvHH tlv; + + if ((len - offset) < sizeof(PkgTlvHH)) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + tlv.type = ReadLE16(data + offset); + tlv.length = ReadLE16(data + offset + sizeof(uint16_t)); + updateInfo_.algorithm->Update({data + offset, sizeof(PkgTlvHH)}, sizeof(PkgTlvHH)); + offset += sizeof(PkgTlvHH); + + if ((len - offset) < tlv.length) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + uint64_t dataLen = ReadLE64(data + offset); + updateInfo_.algorithm->Update({data + offset, tlv.length}, tlv.length); + offset += tlv.length; + + dataLenInfos[patition] = dataLen; + + return true; +} + +bool BinChunkUpdate::VerifySignature(std::vector &signData) +{ + // 计算最终的哈希值 + PkgBuffer digest(DigestAlgorithm::GetDigestLen(PKG_DIGEST_TYPE_SHA256)); + updateInfo_.algorithm->Final(digest); + + // 获取用于验证签名的算法 + SignAlgorithm::SignAlgorithmPtr signAlgorithm = + PkgAlgorithmFactory::GetVerifyAlgorithm(Utils::GetCertName(), PKG_DIGEST_TYPE_SHA256); + if (signAlgorithm == nullptr) { + LOG(ERROR) << "BinChunkUpdate Invalid sign algo"; + return false; + } + + // 验证签名 + if (signAlgorithm->VerifyDigest(digest.data, signData) != 0) { + LOG(ERROR) << "BinChunkUpdate VerifyDigest failed"; + return false; + } + + LOG(INFO) << "BinChunkUpdate VerifyDigest success"; + return true; +} + +bool BinChunkUpdate::VerifyPartitionHashes(const PartitionHashInfo &hashInfos, + std::vector> &futures) +{ + // 使用异步任务来验证每个分区的哈希 + for (const auto &pair : hashInfos.hashValues) { + futures.push_back(std::async(std::launch::async, &BinChunkUpdate::VerifyPartitionHash, this, pair.first, + pair.second, std::ref(hashInfos.dataLenInfos))); + } + + // 等待所有异步任务完成 + for (auto &future : futures) { + if (!future.get()) { + LOG(ERROR) << "BinChunkUpdate partition verify hash fail"; + return false; + } + } + + return true; +} + +UpdateResultCode BinChunkUpdate::UpdateBinOther(uint8_t *data, uint32_t &len) +{ + LOG(DEBUG) << "BinChunkUpdate::UpdateBinOther enter"; + return STREAM_UPDATE_FAILURE; +} + +UpdateResultCode BinChunkUpdate::UpdateBinHead(uint8_t *data, uint32_t &len) +{ + LOG(DEBUG) << "BinChunkUpdate::UpdateBinHead enter"; + 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 STREAM_UPDATE_FAILURE; + } + + 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 STREAM_UPDATE_FAILURE; + } + + const PkgInfo *pkgInfo = pkgManager_->GetPackageInfo(UPDATE_BIN_FILE); + if (pkgInfo == nullptr || pkgInfo->updateFileHeadLen == 0 || len < pkgInfo->updateFileHeadLen) { + LOG(ERROR) << "GetPackageInfo failed"; + return STREAM_UPDATE_FAILURE; + } + offset_ = pkgInfo->updateFileHeadLen; + LOG(DEBUG) << "BinChunkUpdate::UpdateBinHead exit pkgInfo->updateFileHeadLen:" << pkgInfo->updateFileHeadLen; + return STREAM_UPDATE_SUCCESS; +} + +UpdateResultCode BinChunkUpdate::ChunkInstallPreWrite(uint8_t *data, uint32_t &len) +{ + LOG(DEBUG) << "BinChunkUpdate::ChunkInstallPreWrite enter"; + + if (!ReadPartitionData(data, len)) { + return STREAM_UPDATE_SUCCESS; + } + + if (!OpenDevPath()) { + return STREAM_UPDATE_FAILURE; + } + + if (!InitTransferParams()) { + return STREAM_UPDATE_FAILURE; + } + + updateInfo_.updateStep = CHUNK_INSTALL_STEP_DO; + return STREAM_UPDATE_SUCCESS; +} + +bool BinChunkUpdate::ReadPartitionData(uint8_t *data, uint32_t &len) +{ + PkgTlvHH tlv; + uint32_t offset = offset_; + + if ((len - offset) < sizeof(PkgTlvHH)) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + tlv.type = ReadLE16(data + offset); + tlv.length = ReadLE16(data + offset + sizeof(uint16_t)); + offset += sizeof(PkgTlvHH); + + if ((len - offset) < tlv.length) { + updateInfo_.needNewData = true; + return false; + } + + updateInfo_.curPartition = ""; + PkgFileImpl::ConvertBufferToString(updateInfo_.curPartition, {data + offset, tlv.length}); + LOG(DEBUG) << "PreWriteBin name " << updateInfo_.curPartition; + + return true; +} + +bool BinChunkUpdate::OpenDevPath() +{ + #ifndef UPDATER_UT + std::string devPath = GetBlockDeviceByMountPoint(updateInfo_.curPartition); + std::string srcPath; + std::string targetPath; + srcPath = devPath; + targetPath = devPath; + + if (updateInfo_.curPartition != "/userdata") { + std::string suffix = ""; + GetPartitionSuffix(suffix); + targetPath += suffix; + GetActivePartitionSuffix(suffix); + srcPath += suffix; + } + + LOG(DEBUG) << "ChunkInstallPreWrite curPartition:" << updateInfo_.curPartition + << " srcPath:" << srcPath << " targetPath:" << targetPath; + + updateInfo_.srcFd = open(srcPath.c_str(), O_RDWR | O_LARGEFILE); + if (updateInfo_.srcFd < 0) { + LOG(ERROR) << "open srcPath error"; + return false; + } + + updateInfo_.targetFd = open(targetPath.c_str(), O_RDWR | O_LARGEFILE); + if (updateInfo_.targetFd < 0) { + LOG(ERROR) << "open targetPath error"; + return false; + } + #else + int fd = open("/data/updater/test.txt", O_RDWR | O_LARGEFILE | O_CREAT); + if (fd < 0) { + LOG(ERROR) << "open test file error"; + return false; + } + updateInfo_.srcFd = fd; + updateInfo_.targetFd = fd; + #endif + return true; +} + +bool BinChunkUpdate::InitTransferParams() +{ + updateInfo_.transferParams = std::make_unique(); + updateInfo_.transferParams->storeBase = std::string("/data/updater/") + updateInfo_.curPartition + "_tmp"; + updateInfo_.transferParams->canWrite = true; + + int32_t ret = Store::CreateNewSpace(updateInfo_.transferParams->storeBase, true); + if (ret == -1) { + LOG(ERROR) << "Error to create new store space"; + return false; + } + + return true; +} + +UpdateResultCode BinChunkUpdate::ChunkInstallDoWrite(uint8_t *data, uint32_t &len) +{ + LOG(DEBUG) << "BinChunkUpdate::ChunkInstallDoWrite enter"; + uint32_t offset = offset_; + + // 处理安装分区 + if (!ProcessPartition(data, len, offset)) { + return STREAM_UPDATE_SUCCESS; + } + + // 处理安装命令 + if (!ProcessCmdLine(data, len, offset)) { + return STREAM_UPDATE_SUCCESS; + } + + // 处理安装数据 + if (!ProcessInstallData(data, len, offset)) { + return STREAM_UPDATE_SUCCESS; + } + + // 安装数据 + if (!ExecuteCmdLine()) { + return STREAM_UPDATE_FAILURE; + } + + offset_ = offset; + return STREAM_UPDATE_SUCCESS; +} + +bool BinChunkUpdate::ProcessPartition(uint8_t *data, uint32_t &len, uint32_t &offset) +{ + PkgTlvHH tlv; + if ((len - offset) < sizeof(PkgTlvHH)) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + tlv.type = ReadLE16(data + offset); + LOG(DEBUG) << "tlv.type:" << tlv.type; + if (tlv.type == BIN_UPDATE_HASH_TIP) { + updateInfo_.updateStep = CHUNK_INSTALL_STEP_POST; + return false; + } + + tlv.length = ReadLE16(data + offset + sizeof(uint16_t)); + LOG(DEBUG) << "tlv.length:" << tlv.length; + offset += sizeof(PkgTlvHH); + + if ((len - offset) < tlv.length) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + std::string partition; + PkgFileImpl::ConvertBufferToString(partition, {data + offset, tlv.length}); + LOG(DEBUG) << "partition:" << partition; + offset += tlv.length; + + if (partition != updateInfo_.curPartition) { + updateInfo_.updateStep = CHUNK_INSTALL_STEP_POST; + return false; + } + + return true; +} + +bool BinChunkUpdate::ProcessCmdLine(uint8_t *data, uint32_t &len, uint32_t &offset) +{ + PkgTlvHH tlv; + if ((len - offset) < sizeof(PkgTlvHH)) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + tlv.type = ReadLE16(data + offset); + LOG(DEBUG) << "tlv.type:" << tlv.type; + tlv.length = ReadLE16(data + offset + sizeof(uint16_t)); + LOG(DEBUG) << "tlv.length:" << tlv.length; + offset += sizeof(PkgTlvHH); + + if ((len - offset) < tlv.length) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + updateInfo_.cmdLine = ""; + PkgFileImpl::ConvertBufferToString(updateInfo_.cmdLine, {data + offset, tlv.length}); + LOG(DEBUG) << "cmdLine:" << updateInfo_.cmdLine; + offset += tlv.length; + + return true; +} + +bool BinChunkUpdate::ProcessInstallData(uint8_t *data, uint32_t &len, uint32_t &offset) +{ + PkgTlvHI tlv2; + if ((len - offset) < sizeof(PkgTlvHI)) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + tlv2.type = ReadLE16(data + offset); + LOG(DEBUG) << "tlv2.type:" << tlv2.type; + tlv2.length = ReadLE32(data + offset + sizeof(uint16_t)); + LOG(DEBUG) << "tlv2.length:" << tlv2.length; + offset += sizeof(PkgTlvHI); + + if ((len - offset) < tlv2.length) { + LOG(DEBUG) << "needNewData"; + updateInfo_.needNewData = true; + return false; + } + + updateInfo_.transferParams->dataBuffer = data + offset; + updateInfo_.transferParams->dataBufferSize = tlv2.length; + + offset += tlv2.length; + return true; +} + +bool BinChunkUpdate::ExecuteCmdLine() +{ + std::shared_ptr cmd = std::make_shared(updateInfo_.transferParams.get()); + cmd->SetIsStreamCmd(true); + cmd->SetSrcFileDescriptor(updateInfo_.srcFd); + cmd->SetTargetFileDescriptor(updateInfo_.targetFd); + cmd->Init(updateInfo_.cmdLine); + + CommandFunction *cf = CommandFunctionFactory::GetInstance().GetCommandFunction(cmd->GetCommandHead()); + CommandResult ret = cf->Execute(const_cast(*cmd.get())); + if (SUCCESS != ret) { + LOG(ERROR) << "cf->Execute fail"; + return false; + } + + LOG(INFO) << "cf->Execute SUCCESS"; + return true; +} + +UpdateResultCode BinChunkUpdate::ChunkInstallPostWrite(uint8_t *data, uint32_t &len) +{ + LOG(DEBUG) << "BinChunkUpdate::ChunkInstallPostWrite enter"; + if (updateInfo_.srcFd > 0) { + fsync(updateInfo_.srcFd); + close(updateInfo_.srcFd); + } + if (updateInfo_.targetFd > 0) { + fsync(updateInfo_.targetFd); + close(updateInfo_.targetFd); + } + Store::DoFreeSpace(updateInfo_.transferParams->storeBase); + (void)Utils::DeleteFile(updateInfo_.transferParams->storeBase); + updateInfo_.updateStep = CHUNK_INSTALL_STEP_PRE; + return STREAM_UPDATE_SUCCESS; +} + +UpdateResultCode BinChunkUpdate::UpdateBinData(uint8_t *data, uint32_t &len) +{ + LOG(DEBUG) << "BinChunkUpdate::UpdateBinData enter"; + UpdateResultCode ret; + do { + auto it = chunkInstallProcess_.find(updateInfo_.updateStep); + if (it == chunkInstallProcess_.end() || it->second == nullptr) { + LOG(ERROR) << "cannot find " << updateInfo_.updateStep; + return STREAM_UPDATE_FAILURE; + } + ret = it->second(data, len); + } while (!(updateInfo_.needNewData || ret == STREAM_UPDATE_FAILURE || + updateInfo_.updateStep == CHUNK_INSTALL_STEP_PRE)); + + LOG(DEBUG) << "BinChunkUpdate::UpdateBinData exit"; + return ret; +} + +// 计算文件哈希值的函数 +std::string BinChunkUpdate::ComputeFileHash(const std::string &partitionName, + const std::map &dataLenInfos) +{ + LOG(DEBUG) << "BinChunkUpdate::ComputeFileHash enter"; + std::vector hash(SHA256_DIGEST_LENGTH); + + auto it = dataLenInfos.find(partitionName); + if (it == dataLenInfos.end()) { + LOG(ERROR) << "ComputeFileHash cannot find dataLenInfos " << partitionName; + return ""; + } + uint64_t dataLen = it->second; + #ifndef UPDATER_UT + std::string devPath = GetBlockDeviceByMountPoint(partitionName); + if (partitionName != "/userdata") { + std::string suffix = ""; + GetPartitionSuffix(suffix); + devPath += suffix; + } + #else + std::string devPath = "/data/updater/test.txt"; + #endif + std::ifstream file(devPath, std::ios::binary); + if (!file) { + LOG(ERROR) << "Failed to open file: " << partitionName; + return ""; + } + + SHA256_CTX sha256; + SHA256_Init(&sha256); + + while (dataLen > 0) { + std::vector buffer(HASH_BUFFER_SIZE); + size_t size = std::min(static_cast(dataLen), buffer.size()); + file.read(buffer.data(), size); + SHA256_Update(&sha256, buffer.data(), file.gcount()); + dataLen -= file.gcount(); + } + + SHA256_Final(hash.data(), &sha256); + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + const int kByteWidth = 2; + for (auto byte : hash) { + oss << std::setw(kByteWidth) << static_cast(byte); + } + + return oss.str(); +} + +// 比对哈希值的函数 +bool BinChunkUpdate::VerifyPartitionHash(const std::string &partitionName, const std::string &expectedHash, + const std::map &dataLenInfos) +{ + LOG(DEBUG) << "BinChunkUpdate::VerifyPartitionHash enter"; + std::string actualHash = ComputeFileHash(partitionName, dataLenInfos); + + LOG(DEBUG) << "actualHash:" << actualHash << " expectedHash:" << expectedHash; + + if (actualHash != expectedHash) { + LOG(ERROR) << "Error verifying hash for partition " << partitionName; + return false; + } + return true; +} + +} // namespace Updater diff --git a/services/stream_update/bin_chunk_update.h b/services/stream_update/bin_chunk_update.h new file mode 100755 index 0000000000000000000000000000000000000000..c9710b5449f015d06226d241a0c36b17bba6780e --- /dev/null +++ b/services/stream_update/bin_chunk_update.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2025 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. + */ +#ifndef BIN_CHUNK_UPDATE +#define BIN_CHUNK_UPDATE + +#include +#include +#include +#include +#include +#include +#include + +#include "package/pkg_manager.h" +#include "applypatch/transfer_manager.h" +#include "pkg_package/pkg_pkgfile.h" +#include "pkg_manager/pkg_stream.h" + +namespace Updater { + +struct __attribute__((packed)) PkgTlvHH { + uint16_t type; + uint16_t length; +}; + +struct __attribute__((packed)) PkgTlvHI { + uint16_t type; + uint32_t length; +}; + +using UpdateResultCode = enum { + STREAM_UPDATE_SUCCESS = 0, + STREAM_UPDATE_FAILURE = 1, + STREAM_UPDATE_COMPLETE = 2 +}; + +using BinUpdateTip = enum { + BIN_UPDATE_HEAD_TIP = 0x01, + BIN_UPDATE_DATA_TIP = 0x12, + BIN_UPDATE_HASH_TIP = 0x16 +}; + +using ChunkInstallStep = enum { + CHUNK_INSTALL_STEP_PRE = 0, + CHUNK_INSTALL_STEP_DO, + CHUNK_INSTALL_STEP_POST +}; + +struct BinChunkUpdateInfo { + std::vector componentNames; + bool needNewData = false; + ChunkInstallStep updateStep = CHUNK_INSTALL_STEP_PRE; + int srcFd; + int targetFd; + std::unique_ptr transferParams; + std::string curPartition; + std::string cmdLine; + int patitionNum; + Hpackage::DigestAlgorithm::DigestAlgorithmPtr algorithm; +}; + +struct PartitionHashInfo { + std::map hashValues; + std::map dataLenInfos; +}; + +class BinChunkUpdate { +public: + explicit BinChunkUpdate(uint32_t maxBufSize); + virtual ~BinChunkUpdate(); + UpdateResultCode StartBinChunkUpdate(const uint8_t *data, uint32_t len, uint32_t &dealLen); +private: + UpdateResultCode ProcessBufferData(); + + UpdateResultCode ChunkInstallPreWrite(uint8_t *data, uint32_t &len); + UpdateResultCode ChunkInstallDoWrite(uint8_t *data, uint32_t &len); + UpdateResultCode ChunkInstallPostWrite(uint8_t *data, uint32_t &len); + + UpdateResultCode UpdateBinHead(uint8_t *data, uint32_t &len); + UpdateResultCode UpdateBinData(uint8_t *data, uint32_t &len); + UpdateResultCode UpdateBinHash(uint8_t *data, uint32_t &len); + UpdateResultCode UpdateBinOther(uint8_t *data, uint32_t &len); + + bool AddRemainData(const uint8_t *data, uint32_t &len); + bool MoveRemainingData(); + + bool ReadPartitionData(uint8_t *data, uint32_t &len); + bool OpenDevPath(); + bool InitTransferParams(); + + // 处理安装分区 + bool ProcessPartition(uint8_t *data, uint32_t &len, uint32_t &offset); + // 处理安装命令 + bool ProcessCmdLine(uint8_t *data, uint32_t &len, uint32_t &offset); + // 处理安装数据 + bool ProcessInstallData(uint8_t *data, uint32_t &len, uint32_t &offset); + // 执行安装命令 + bool ExecuteCmdLine(); + + bool ProcessPartitionNum(uint8_t *data, uint32_t &len, uint32_t &offset); + + bool ProcessPartitionData(uint8_t *data, uint32_t &len, uint32_t &offset, PartitionHashInfo &hashInfos); + + bool ProcessSignature(uint8_t *data, uint32_t &len, uint32_t &offset, + std::vector &signData); + + bool ReadHash(uint8_t *data, uint32_t &len, uint32_t &offset, std::string &hashBuf); + + bool ReadDataLength(uint8_t *data, uint32_t &len, uint32_t &offset, + const std::string &patition, std::map &dataLenInfos); + + bool VerifySignature(std::vector &signData); + + bool VerifyPartitionHashes(const PartitionHashInfo &hashInfos, std::vector> &futures); + + bool VerifyPartitionHash(const std::string& partitionName, const std::string &expectedHash, + const std::map &dataLenInfos); + std::string ComputeFileHash(const std::string& partitionName, const std::map &dataLenInfos); + + Hpackage::PkgManager::PkgManagerPtr pkgManager_; + uint8_t *buffer_ = nullptr; + uint32_t maxBufSize_ = 0; + uint32_t curlen_ = 0; + uint32_t offset_ = 0; + + std::map> chunkInstallProcess_; + BinChunkUpdateInfo updateInfo_ {}; +}; +} // Updater +#endif /* BIN_FLOW_UPDATE */ diff --git a/services/updater_binary/update_image_block.cpp b/services/updater_binary/update_image_block.cpp index 50b7d661abf86c727378609116397a6c3cab2639..c0953a4e154aa3270e8c1269d2bb58fdd420246c 100644 --- a/services/updater_binary/update_image_block.cpp +++ b/services/updater_binary/update_image_block.cpp @@ -30,6 +30,7 @@ #include "updater/updater_const.h" #include "updater/hwfault_retry.h" #include "utils.h" +#include "slot_info/slot_info.h" using namespace Uscript; using namespace Hpackage; @@ -177,6 +178,15 @@ static int32_t GetUpdateBlockInfo(struct UpdateBlockInfo &infos, Uscript::UScrip LOG(INFO) << "ExecuteUpdateBlock::updating " << infos.partitionName << " ..."; infos.devPath = GetBlockDeviceByMountPoint(infos.partitionName); +#ifndef UPDATER_UT + if (infos.partitionName != "/userdata") { + std::string suffix = ""; + GetPartitionSuffix(suffix); + infos.devPath += suffix; + } +#else + infos.devPath = "/data/updater" + infos.partitionName; +#endif LOG(INFO) << "ExecuteUpdateBlock::updating dev path : " << infos.devPath; if (infos.devPath.empty()) { LOG(ERROR) << "cannot get block device of partition"; @@ -373,7 +383,7 @@ static int32_t ExecuteUpdateBlock(Uscript::UScriptEnv &env, Uscript::UScriptCont LOG(INFO) << "Start unpack new data thread done. Get patch data: " << infos.patchDataName; if (ExtractFileByName(env, infos.patchDataName, outStream, - transferParams->patchDataBuffer, transferParams->patchDataSize) != USCRIPT_SUCCESS) { + transferParams->dataBuffer, transferParams->dataBufferSize) != USCRIPT_SUCCESS) { return USCRIPT_ERROR_EXECUTE; } @@ -452,6 +462,15 @@ int32_t UScriptInstructionBlockCheck::Execute(Uscript::UScriptEnv &env, Uscript: return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context); } auto devPath = GetBlockDeviceByMountPoint(partitionName); +#ifndef UPDATER_UT + if (partitionName != "/userdata") { + std::string suffix = ""; + GetPartitionSuffix(suffix); + devPath += suffix; + } +#else + devPath = "/data/updater" + partitionName; +#endif LOG(INFO) << "UScriptInstructionBlockCheck::dev path : " << devPath; time_t mountTime = 0; uint16_t mountCount = 0; @@ -712,6 +731,16 @@ int32_t UScriptInstructionShaCheck::Execute(Uscript::UScriptEnv &env, Uscript::U UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE, "cannot get block device of partition"); return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context); } +#ifndef UPDATER_UT + if (partitionName != "/userdata") { + std::string suffix = ""; + GetPartitionSuffix(suffix); + devPath += suffix; + } + LOG(INFO) << "write partition path: " << devPath; +#else + devPath = "/data/updater" + partitionName; +#endif ret = ExecReadShaInfo(env, devPath, shaInfo, partitionName); return ReturnAndPushParam(ret, context); } diff --git a/services/updater_binary/update_image_patch.cpp b/services/updater_binary/update_image_patch.cpp index 5a067636bb891e22b37e3e5871979b09ae5c63b0..5ce712dded0970f3c9c9a190f833553bb9261214 100644 --- a/services/updater_binary/update_image_patch.cpp +++ b/services/updater_binary/update_image_patch.cpp @@ -35,6 +35,7 @@ #include "updater/updater_const.h" #include "updater/hwfault_retry.h" #include "utils.h" +#include "slot_info/slot_info.h" using namespace Uscript; using namespace Hpackage; @@ -70,6 +71,15 @@ int32_t USInstrImagePatch::GetParam(Uscript::UScriptContext &context, ImagePatch return USCRIPT_INVALID_PARAM; } para.devPath = GetBlockDeviceByMountPoint(para.partName); +#ifndef UPDATER_UT + if (para.partName != "/userdata") { + std::string suffix = ""; + GetPartitionSuffix(suffix); + para.devPath += suffix; + } +#else + para.devPath = "/data/updater" + para.partName; +#endif if (para.devPath.empty()) { LOG(ERROR) << "get " << para.partName << " dev path error"; return USCRIPT_ERROR_EXECUTE; @@ -252,6 +262,15 @@ int32_t USInstrImageShaCheck::GetParam(Uscript::UScriptContext &context, CheckPa } para.devPath = GetBlockDeviceByMountPoint(para.partName); +#ifndef UPDATER_UT + if (para.partName != "/userdata") { + std::string suffix = ""; + GetPartitionSuffix(suffix); + para.devPath += suffix; + } +#else + para.devPath = "/data/updater" + para.partName; +#endif if (para.devPath.empty()) { LOG(ERROR) << "cannot get block device of partition" << para.partName; return USCRIPT_ERROR_EXECUTE; diff --git a/test/unittest/applypatch_test/blockset_unittest.cpp b/test/unittest/applypatch_test/blockset_unittest.cpp index 06b84082d702e9e8a33dc2d0dfa7fd0c490d1a31..dca30b237a5bb1d82f3b2fe39bd5c036b076d186 100755 --- a/test/unittest/applypatch_test/blockset_unittest.cpp +++ b/test/unittest/applypatch_test/blockset_unittest.cpp @@ -124,7 +124,8 @@ HWTEST_F(BlockSetUnitTest, blockset_test_005, TestSize.Level1) transferParams->writerThreadInfo = std::make_unique(); Command *cmd = new Command(transferParams.get()); cmd->Init(cmdLine); - cmd->SetFileDescriptor(fd); + cmd->SetSrcFileDescriptor(fd); + cmd->SetTargetFileDescriptor(fd); BlockSet targetBlock; size_t blockSize = H_BLOCK_SIZE; std::vector srcBuffer(blockSize); diff --git a/test/unittest/applypatch_test/commandsfunction_unittest.cpp b/test/unittest/applypatch_test/commandsfunction_unittest.cpp index 00cfadd15a80e5990e1d5e7194f7f0687a47dbbe..ddb917a80b8c6424672b4439eb55e3d25c65f1c3 100644 --- a/test/unittest/applypatch_test/commandsfunction_unittest.cpp +++ b/test/unittest/applypatch_test/commandsfunction_unittest.cpp @@ -74,7 +74,8 @@ HWTEST_F(CommandFunctionUnitTest, command_function_test_001, TestSize.Level1) return; } lseek64(fd, 0, SEEK_SET); - cmd->SetFileDescriptor(fd); + cmd->SetSrcFileDescriptor(fd); + cmd->SetTargetFileDescriptor(fd); std::string cmdLine = std::string("erase 2,0,1"); CommandResult ret = CommandFunctionUnitTest::TestCommandFnExec(cmd, cmdLine); EXPECT_EQ(ret, 0); diff --git a/test/unittest/stream_update/BUILD.gn b/test/unittest/stream_update/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..0bfc40a22048b9239fa090f1d0ca850895f6ec89 --- /dev/null +++ b/test/unittest/stream_update/BUILD.gn @@ -0,0 +1,71 @@ +# 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. + +import("//base/update/updater/updater_default_cfg.gni") +import("//build/test.gni") + +MODULE_OUTPUT_PATH = "updater/updater_test" +updater_path = rebase_path("${updater_absolutely_path}", ".") + +ohos_unittest("bin_chunk_update_test") { + testonly = true + resource_config_file = "${updater_path}/test/unittest/test_data/ohos_test.xml" + module_out_path = MODULE_OUTPUT_PATH + sources = [ + "${updater_path}/services/stream_update/bin_chunk_update.cpp", + "${updater_path}/utils/utils.cpp", + "bin_chunk_update_unittest.cpp", + ] + + include_dirs = [ + "${updater_path}/services/stream_update", + "${updater_path}/services", + "${updater_path}/services/common", + "${updater_path}/services/include", + "${updater_path}/services/include/applypatch", + "${updater_path}/services/include/log", + "${updater_path}/services/include/package", + "${updater_path}/services/include/script", + "${updater_path}/services/package", + "${updater_path}/services/package/pkg_algorithm", + "${updater_path}/services/package/pkg_manager", + "${updater_path}/services/package/pkg_package", + "${updater_path}/services/script", + ] + + deps = [ + "${updater_path}/interfaces/kits/packages:libpackageExt", + "${updater_path}/services:libupdater", + "${updater_path}/services/applypatch:libapplypatch", + "${updater_path}/services/fs_manager:libfsmanager", + "${updater_path}/services/log:libupdaterlog", + "${updater_path}/services/package:libupdaterpackage", + "${updater_path}/services/stream_update:libbinchunkupdate", + "${updater_path}/utils:libutils", + ] + external_deps = [ + "bounds_checking_function:libsec_static", + "bzip2:libbz2", + "cJSON:cjson", + "googletest:gmock_main", + "googletest:gtest_main", + "hilog:libhilog", + "init:libbegetutil_static", + "init:libfsmanager_static_real", + "openssl:libcrypto_shared", + ] + defines = [ "UPDATER_UT" ] + configs = [ "${updater_path}/test/unittest:utest_config" ] + install_enable = true + part_name = "updater" +} diff --git a/test/unittest/stream_update/bin_chunk_update_unittest.cpp b/test/unittest/stream_update/bin_chunk_update_unittest.cpp new file mode 100755 index 0000000000000000000000000000000000000000..1aa73b61717529c026a587fb995ff9835cbf7c77 --- /dev/null +++ b/test/unittest/stream_update/bin_chunk_update_unittest.cpp @@ -0,0 +1,73 @@ +/* + * 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 +#include + +#include "bin_chunk_update.h" +#include "log.h" + +using namespace testing::ext; +using namespace Hpackage; +using namespace Updater; + +namespace OHOS { +constexpr const char *PKG_PATH = "/data/updater/package/update_stream.bin"; +constexpr uint32_t BUFFER_SIZE = 50 * 1024; +class BinChunkUpdateTest : public testing::Test { +public: + static void SetUpTestCase(void) {} + static void TearDownTestCase(void) {} + void SetUp() {} + void TearDown() {} +}; + +HWTEST_F(BinChunkUpdateTest, binChunkUpdateTest01, TestSize.Level0) +{ + LOG(INFO) << "binChunkUpdateTest01 start"; + uint32_t dealLen = 0; + //错误数据 + uint8_t buffer[BUFFER_SIZE] = {0, 'a', 1, 'b', 2}; + BinChunkUpdate binChunkUpdate(2 * BUFFER_SIZE); + UpdateResultCode ret = binChunkUpdate.StartBinChunkUpdate(buffer, 5, dealLen); + EXPECT_EQ(ret, STREAM_UPDATE_FAILURE); +} + +HWTEST_F(BinChunkUpdateTest, binChunkUpdateTest02, TestSize.Level0) +{ + LOG(INFO) << "binChunkUpdateTest02 start"; + uint32_t dealLen = 0; + FILE* fp = fopen(PKG_PATH, "rb"); + if (fp == nullptr) { + std::cout << "fopen /data/updater/package/update_stream.bin failed" << " : " << strerror(errno); + ASSERT_NE(fp, nullptr) << "Failed to open file: " << PKG_PATH; + } + EXPECT_NE(fp, nullptr); + + uint8_t buffer[BUFFER_SIZE]{0}; + size_t len; + int ret = 0; + BinChunkUpdate binChunkUpdate(2 * BUFFER_SIZE); + while ((len = fread(buffer, 1, sizeof(buffer), fp)) != 0) { + ret = binChunkUpdate.StartBinChunkUpdate(buffer, len, dealLen); + + if (ret != STREAM_UPDATE_SUCCESS) { + break; + } + } + + EXPECT_EQ(ret, STREAM_UPDATE_COMPLETE); +} +} // namespace OHOS diff --git a/test/unittest/test_data/ohos_test.xml b/test/unittest/test_data/ohos_test.xml index ff6e6bd945710a34dae42f994cc02cab0fc02bea..8b861b3094b46de1c027b372ea949cd352524c61 100644 --- a/test/unittest/test_data/ohos_test.xml +++ b/test/unittest/test_data/ohos_test.xml @@ -233,6 +233,12 @@