1 /*
2 * Copyright (c) 2025 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 #include "bin_chunk_update.h"
16
17 #include <algorithm>
18 #include <fcntl.h>
19 #include <functional>
20 #include <iomanip> // 用于 std::setw 和 std::setfill
21 #include <iostream>
22 #include <sstream> // 用于 std::ostringstream
23 #include <sys/stat.h>
24
25 #include "applypatch/command_process.h"
26 #include "applypatch/store.h"
27 #include "fs_manager/mount.h"
28 #include "log.h"
29 #include "scope_guard.h"
30 #include "slot_info/slot_info.h"
31 #include "utils.h"
32
33 namespace Updater {
34 using namespace Uscript;
35 using namespace Hpackage;
36 using namespace std::placeholders;
37
38 constexpr const char *UPDATE_BIN_FILE = "update.bin";
39 constexpr const size_t HASH_BUFFER_SIZE = 50 * 1024;
BinChunkUpdate(uint32_t maxBufSize)40 BinChunkUpdate::BinChunkUpdate(uint32_t maxBufSize)
41 {
42 LOG(DEBUG) << "BinChunkUpdate::BinChunkUpdate enter";
43 maxBufSize_ = maxBufSize;
44 buffer_ = new uint8_t[maxBufSize_];
45 chunkInstallProcess_.emplace(CHUNK_INSTALL_STEP_PRE, [this](uint8_t *data, uint32_t &len) {
46 return this->ChunkInstallPreWrite(data, len);
47 });
48 chunkInstallProcess_.emplace(CHUNK_INSTALL_STEP_DO, [this](uint8_t *data, uint32_t &len) {
49 return this->ChunkInstallDoWrite(data, len);
50 });
51 chunkInstallProcess_.emplace(CHUNK_INSTALL_STEP_POST, [this](uint8_t *data, uint32_t &len) {
52 return this->ChunkInstallPostWrite(data, len);
53 });
54 pkgManager_ = PkgManager::CreatePackageInstance();
55 }
56
~BinChunkUpdate()57 BinChunkUpdate::~BinChunkUpdate()
58 {
59 PkgManager::ReleasePackageInstance(pkgManager_);
60 if (buffer_ != nullptr) {
61 delete[] buffer_;
62 buffer_ = nullptr;
63 }
64 }
65
StartBinChunkUpdate(const uint8_t * data,uint32_t len,uint32_t & dealLen)66 UpdateResultCode BinChunkUpdate::StartBinChunkUpdate(const uint8_t *data, uint32_t len, uint32_t &dealLen)
67 {
68 LOG(DEBUG) << "BinChunkUpdate::StartBinChunkUpdate enter";
69 UpdateResultCode ret = STREAM_UPDATE_SUCCESS;
70 if (data == nullptr || len == 0 || pkgManager_ == nullptr) {
71 LOG(ERROR) << "para error";
72 return STREAM_UPDATE_FAILURE;
73 }
74 uint32_t remainLen = len;
75 uint32_t leftLen = curlen_;
76 LOG(DEBUG) << "BinChunkUpdate::StartBinChunkUpdate leftLen:" << leftLen;
77 dealLen = 0;
78 while (remainLen > 0) {
79 if (!AddRemainData(data + len - remainLen, remainLen)) {
80 LOG(ERROR) << "AddRemainData error";
81 return STREAM_UPDATE_FAILURE;
82 }
83 updateInfo_.needNewData = false;
84
85 // 处理缓冲区的数据
86 ret = ProcessBufferData();
87 if (ret == STREAM_UPDATE_FAILURE) {
88 return ret;
89 }
90
91 // 移动剩余数据
92 if (!MoveRemainingData()) {
93 return STREAM_UPDATE_FAILURE;
94 }
95 }
96
97 dealLen = len + leftLen - curlen_;
98 LOG(DEBUG) << "BinChunkUpdate StartBinChunkUpdate dealLen:" << dealLen << " len:" << len << " curlen_:" << curlen_
99 << " leftLen:" << leftLen;
100 return ret;
101 }
102
ProcessBufferData()103 UpdateResultCode BinChunkUpdate::ProcessBufferData()
104 {
105 UpdateResultCode ret = STREAM_UPDATE_SUCCESS;
106 while ((curlen_ - offset_) > 0 && !updateInfo_.needNewData) {
107 LOG(DEBUG) << "BinChunkUpdate::StartBinChunkUpdate curlen_:" << curlen_ << " offset_:" << offset_;
108 uint16_t type = ReadLE16(buffer_ + offset_);
109 LOG(DEBUG) << "BinChunkUpdate::StartBinChunkUpdate type:" << type;
110
111 switch (type) {
112 case BIN_UPDATE_HEAD_TIP:
113 ret = UpdateBinHead(buffer_, curlen_);
114 break;
115 case BIN_UPDATE_DATA_TIP:
116 ret = UpdateBinData(buffer_, curlen_);
117 break;
118 case BIN_UPDATE_HASH_TIP:
119 ret = UpdateBinHash(buffer_, curlen_);
120 break;
121 default:
122 ret = UpdateBinOther(buffer_, curlen_);
123 break;
124 }
125
126 if (ret == STREAM_UPDATE_FAILURE) {
127 LOG(ERROR) << "Update failed for type: " << type;
128 return ret;
129 }
130 }
131
132 return ret;
133 }
134
MoveRemainingData()135 bool BinChunkUpdate::MoveRemainingData()
136 {
137 LOG(DEBUG) << "curlen_:" << curlen_ << " offset_:" << offset_;
138
139 if ((curlen_ - offset_) > 0) {
140 if (memmove_s(buffer_, curlen_, buffer_ + offset_, curlen_ - offset_) != EOK) {
141 LOG(ERROR) << "memmove failed";
142 return false;
143 }
144 curlen_ -= offset_;
145 } else {
146 if (memset_s(buffer_, maxBufSize_, 0, maxBufSize_) != 0) {
147 LOG(ERROR) << "memset_s failed";
148 return false;
149 }
150 curlen_ = 0;
151 }
152
153 return true;
154 }
155
AddRemainData(const uint8_t * data,uint32_t & len)156 bool BinChunkUpdate::AddRemainData(const uint8_t *data, uint32_t &len)
157 {
158 if (data == nullptr || len == 0) {
159 LOG(ERROR) << "AddRemainData para error";
160 return false;
161 }
162 uint32_t copySize = std::min(static_cast<size_t>(len), static_cast<size_t>(maxBufSize_ - curlen_));
163 LOG(DEBUG) << "BinChunkUpdate AddRemainData curlen_:" << curlen_ << " copySize:" << copySize;
164 if (memcpy_s(buffer_ + curlen_, maxBufSize_, data, copySize) != EOK) {
165 LOG(ERROR) << "AddRemainData memcpy failed" << " : " << strerror(errno);
166 return false;
167 }
168 curlen_ += copySize;
169 len -= copySize;
170 offset_ = 0;
171 return true;
172 }
173
UpdateBinHash(uint8_t * data,uint32_t & len)174 UpdateResultCode BinChunkUpdate::UpdateBinHash(uint8_t *data, uint32_t &len)
175 {
176 LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash enter";
177 uint32_t offset = offset_;
178 PartitionHashInfo hashInfos;
179 std::vector<uint8_t> signData;
180 std::vector<std::future<bool>> futures;
181
182 // 初始化 SHA256 算法
183 updateInfo_.algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(PKG_DIGEST_TYPE_SHA256);
184 if (updateInfo_.algorithm == nullptr) {
185 LOG(ERROR) << "algorithm is null";
186 return STREAM_UPDATE_FAILURE;
187 }
188 updateInfo_.algorithm->Init();
189
190 // 读取分区数量
191 if (!ProcessPartitionNum(data, len, offset)) {
192 return STREAM_UPDATE_SUCCESS;
193 }
194
195 // 读取分区hash数据
196 if (!ProcessPartitionData(data, len, offset, hashInfos)) {
197 return STREAM_UPDATE_SUCCESS;
198 }
199
200 // 读取签名
201 if (!ProcessSignature(data, len, offset, signData)) {
202 return STREAM_UPDATE_SUCCESS;
203 }
204
205 offset_ = offset;
206
207 // 签名验证
208 if (!VerifySignature(signData)) {
209 return STREAM_UPDATE_FAILURE;
210 }
211
212 // 完整性验证(异步处理哈希验证)
213 if (!VerifyPartitionHashes(hashInfos, futures)) {
214 return STREAM_UPDATE_FAILURE;
215 }
216
217 //切换ab分区
218 #ifndef UPDATER_UT
219 SetActiveSlot();
220 #else
221 int result = remove("/data/updater/test.txt");
222 if (result != 0) {
223 LOG(ERROR) << "Failed to remove /data/updater/test.txt, error: " << strerror(errno);
224 }
225 #endif
226 LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash exit";
227 return STREAM_UPDATE_COMPLETE;
228 }
229
ProcessPartitionNum(uint8_t * data,uint32_t & len,uint32_t & offset)230 bool BinChunkUpdate::ProcessPartitionNum(uint8_t *data, uint32_t &len, uint32_t &offset)
231 {
232 PkgTlvHH tlv;
233
234 // 读取TLV头部信息
235 if ((len - offset) < sizeof(PkgTlvHH)) {
236 LOG(DEBUG) << "needNewData";
237 updateInfo_.needNewData = true;
238 return false;
239 }
240
241 tlv.type = ReadLE16(data + offset);
242 LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash tlv.type:" << tlv.type;
243 tlv.length = ReadLE16(data + offset + sizeof(uint16_t));
244 LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash tlv.length:" << tlv.length;
245 updateInfo_.algorithm->Update({data + offset, sizeof(PkgTlvHH)}, sizeof(PkgTlvHH));
246 offset += sizeof(PkgTlvHH);
247
248 // 读取分区数量
249 if ((len - offset) < tlv.length) {
250 LOG(DEBUG) << "needNewData";
251 updateInfo_.needNewData = true;
252 return false;
253 }
254
255 updateInfo_.patitionNum = ReadLE16(data + offset);
256 LOG(INFO) << "BinChunkUpdate::UpdateBinHash patitionNum:" << updateInfo_.patitionNum;
257 updateInfo_.algorithm->Update({data + offset, tlv.length}, tlv.length);
258 offset += tlv.length;
259
260 return true;
261 }
262
ProcessPartitionData(uint8_t * data,uint32_t & len,uint32_t & offset,PartitionHashInfo & hashInfos)263 bool BinChunkUpdate::ProcessPartitionData(uint8_t *data, uint32_t &len, uint32_t &offset, PartitionHashInfo &hashInfos)
264 {
265 PkgTlvHH tlv;
266
267 for (auto i = 0; i < updateInfo_.patitionNum; i++) {
268 // 读取分区名称
269 if ((len - offset) < sizeof(PkgTlvHH)) {
270 LOG(DEBUG) << "needNewData";
271 updateInfo_.needNewData = true;
272 return false;
273 }
274
275 tlv.type = ReadLE16(data + offset);
276 tlv.length = ReadLE16(data + offset + sizeof(uint16_t));
277 updateInfo_.algorithm->Update({data + offset, sizeof(PkgTlvHH)}, sizeof(PkgTlvHH));
278 offset += sizeof(PkgTlvHH);
279
280 std::string patition;
281 PkgFileImpl::ConvertBufferToString(patition, {data + offset, tlv.length});
282 LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash patition:" << patition;
283 updateInfo_.algorithm->Update({data + offset, tlv.length}, tlv.length);
284 offset += tlv.length;
285
286 // 读取哈希值
287 std::string hashBuf;
288 if (!ReadHash(data, len, offset, hashBuf)) {
289 return false;
290 }
291
292 hashInfos.hashValues[patition] = hashBuf;
293
294 // 读取数据长度
295 if (!ReadDataLength(data, len, offset, patition, hashInfos.dataLenInfos)) {
296 return false;
297 }
298 }
299
300 return true;
301 }
302
ProcessSignature(uint8_t * data,uint32_t & len,uint32_t & offset,std::vector<uint8_t> & signData)303 bool BinChunkUpdate::ProcessSignature(uint8_t *data, uint32_t &len, uint32_t &offset,
304 std::vector<uint8_t> &signData)
305 {
306 PkgTlvHI tlv2;
307
308 if ((len - offset) < sizeof(PkgTlvHI)) {
309 LOG(DEBUG) << "needNewData";
310 updateInfo_.needNewData = true;
311 return false;
312 }
313 tlv2.type = ReadLE16(data + offset);
314 LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash tlv2.type:" << tlv2.type;
315 tlv2.length = ReadLE32(data + offset + sizeof(uint16_t));
316 LOG(DEBUG) << "BinChunkUpdate::UpdateBinHash tlv2.length:" << tlv2.length;
317 offset += sizeof(PkgTlvHI);
318 if ((len - offset) < tlv2.length) {
319 LOG(DEBUG) << "needNewData";
320 updateInfo_.needNewData = true;
321 return false;
322 }
323 signData.assign(data + offset, data + offset + tlv2.length);
324 offset += tlv2.length;
325
326 return true;
327 }
328
ReadHash(uint8_t * data,uint32_t & len,uint32_t & offset,std::string & hashBuf)329 bool BinChunkUpdate::ReadHash(uint8_t *data, uint32_t &len, uint32_t &offset, std::string &hashBuf)
330 {
331 PkgTlvHH tlv;
332
333 if ((len - offset) < sizeof(PkgTlvHH)) {
334 LOG(DEBUG) << "needNewData";
335 updateInfo_.needNewData = true;
336 return false;
337 }
338
339 tlv.type = ReadLE16(data + offset);
340 tlv.length = ReadLE16(data + offset + sizeof(uint16_t));
341 updateInfo_.algorithm->Update({data + offset, sizeof(PkgTlvHH)}, sizeof(PkgTlvHH));
342 offset += sizeof(PkgTlvHH);
343
344 if ((len - offset) < tlv.length) {
345 LOG(DEBUG) << "needNewData";
346 updateInfo_.needNewData = true;
347 return false;
348 }
349
350 PkgFileImpl::ConvertBufferToString(hashBuf, {data + offset, tlv.length});
351 updateInfo_.algorithm->Update({data + offset, tlv.length}, tlv.length);
352 offset += tlv.length;
353
354 return true;
355 }
356
ReadDataLength(uint8_t * data,uint32_t & len,uint32_t & offset,const std::string & patition,std::map<std::string,uint64_t> & dataLenInfos)357 bool BinChunkUpdate::ReadDataLength(uint8_t *data, uint32_t &len, uint32_t &offset,
358 const std::string &patition, std::map<std::string, uint64_t> &dataLenInfos)
359 {
360 PkgTlvHH tlv;
361
362 if ((len - offset) < sizeof(PkgTlvHH)) {
363 LOG(DEBUG) << "needNewData";
364 updateInfo_.needNewData = true;
365 return false;
366 }
367
368 tlv.type = ReadLE16(data + offset);
369 tlv.length = ReadLE16(data + offset + sizeof(uint16_t));
370 updateInfo_.algorithm->Update({data + offset, sizeof(PkgTlvHH)}, sizeof(PkgTlvHH));
371 offset += sizeof(PkgTlvHH);
372
373 if ((len - offset) < tlv.length) {
374 LOG(DEBUG) << "needNewData";
375 updateInfo_.needNewData = true;
376 return false;
377 }
378
379 uint64_t dataLen = ReadLE64(data + offset);
380 updateInfo_.algorithm->Update({data + offset, tlv.length}, tlv.length);
381 offset += tlv.length;
382
383 dataLenInfos[patition] = dataLen;
384
385 return true;
386 }
387
VerifySignature(std::vector<uint8_t> & signData)388 bool BinChunkUpdate::VerifySignature(std::vector<uint8_t> &signData)
389 {
390 // 计算最终的哈希值
391 PkgBuffer digest(DigestAlgorithm::GetDigestLen(PKG_DIGEST_TYPE_SHA256));
392 updateInfo_.algorithm->Final(digest);
393
394 // 获取用于验证签名的算法
395 SignAlgorithm::SignAlgorithmPtr signAlgorithm =
396 PkgAlgorithmFactory::GetVerifyAlgorithm(Utils::GetCertName(), PKG_DIGEST_TYPE_SHA256);
397 if (signAlgorithm == nullptr) {
398 LOG(ERROR) << "BinChunkUpdate Invalid sign algo";
399 return false;
400 }
401
402 // 验证签名
403 if (signAlgorithm->VerifyDigest(digest.data, signData) != 0) {
404 LOG(ERROR) << "BinChunkUpdate VerifyDigest failed";
405 return false;
406 }
407
408 LOG(INFO) << "BinChunkUpdate VerifyDigest success";
409 return true;
410 }
411
VerifyPartitionHashes(const PartitionHashInfo & hashInfos,std::vector<std::future<bool>> & futures)412 bool BinChunkUpdate::VerifyPartitionHashes(const PartitionHashInfo &hashInfos,
413 std::vector<std::future<bool>> &futures)
414 {
415 // 使用异步任务来验证每个分区的哈希
416 for (const auto &pair : hashInfos.hashValues) {
417 futures.push_back(std::async(std::launch::async, &BinChunkUpdate::VerifyPartitionHash, this, pair.first,
418 pair.second, std::ref(hashInfos.dataLenInfos)));
419 }
420
421 // 等待所有异步任务完成
422 for (auto &future : futures) {
423 if (!future.get()) {
424 LOG(ERROR) << "BinChunkUpdate partition verify hash fail";
425 return false;
426 }
427 }
428
429 return true;
430 }
431
UpdateBinOther(uint8_t * data,uint32_t & len)432 UpdateResultCode BinChunkUpdate::UpdateBinOther(uint8_t *data, uint32_t &len)
433 {
434 LOG(DEBUG) << "BinChunkUpdate::UpdateBinOther enter";
435 return STREAM_UPDATE_FAILURE;
436 }
437
UpdateBinHead(uint8_t * data,uint32_t & len)438 UpdateResultCode BinChunkUpdate::UpdateBinHead(uint8_t *data, uint32_t &len)
439 {
440 LOG(DEBUG) << "BinChunkUpdate::UpdateBinHead enter";
441 PkgManager::StreamPtr stream = nullptr;
442 PkgBuffer buffer(data, len);
443 if (auto ret = pkgManager_->CreatePkgStream(stream, UPDATE_BIN_FILE, buffer); ret != PKG_SUCCESS) {
444 LOG(ERROR) << "ParseHead failed";
445 return STREAM_UPDATE_FAILURE;
446 }
447
448 if (auto ret = pkgManager_->LoadPackageWithStream(UPDATE_BIN_FILE, Utils::GetCertName(), updateInfo_.componentNames,
449 PkgFile::PKG_TYPE_UPGRADE, stream); ret != PKG_SUCCESS) {
450 LOG(ERROR) << "LoadPackage fail ret :" << ret;
451 return STREAM_UPDATE_FAILURE;
452 }
453
454 const PkgInfo *pkgInfo = pkgManager_->GetPackageInfo(UPDATE_BIN_FILE);
455 if (pkgInfo == nullptr || pkgInfo->updateFileHeadLen == 0 || len < pkgInfo->updateFileHeadLen) {
456 LOG(ERROR) << "GetPackageInfo failed";
457 return STREAM_UPDATE_FAILURE;
458 }
459 offset_ = pkgInfo->updateFileHeadLen;
460 LOG(DEBUG) << "BinChunkUpdate::UpdateBinHead exit pkgInfo->updateFileHeadLen:" << pkgInfo->updateFileHeadLen;
461 return STREAM_UPDATE_SUCCESS;
462 }
463
ChunkInstallPreWrite(uint8_t * data,uint32_t & len)464 UpdateResultCode BinChunkUpdate::ChunkInstallPreWrite(uint8_t *data, uint32_t &len)
465 {
466 LOG(DEBUG) << "BinChunkUpdate::ChunkInstallPreWrite enter";
467
468 if (!ReadPartitionData(data, len)) {
469 return STREAM_UPDATE_SUCCESS;
470 }
471
472 if (!OpenDevPath()) {
473 return STREAM_UPDATE_FAILURE;
474 }
475
476 if (!InitTransferParams()) {
477 return STREAM_UPDATE_FAILURE;
478 }
479
480 updateInfo_.updateStep = CHUNK_INSTALL_STEP_DO;
481 return STREAM_UPDATE_SUCCESS;
482 }
483
ReadPartitionData(uint8_t * data,uint32_t & len)484 bool BinChunkUpdate::ReadPartitionData(uint8_t *data, uint32_t &len)
485 {
486 PkgTlvHH tlv;
487 uint32_t offset = offset_;
488
489 if ((len - offset) < sizeof(PkgTlvHH)) {
490 LOG(DEBUG) << "needNewData";
491 updateInfo_.needNewData = true;
492 return false;
493 }
494
495 tlv.type = ReadLE16(data + offset);
496 tlv.length = ReadLE16(data + offset + sizeof(uint16_t));
497 offset += sizeof(PkgTlvHH);
498
499 if ((len - offset) < tlv.length) {
500 updateInfo_.needNewData = true;
501 return false;
502 }
503
504 updateInfo_.curPartition = "";
505 PkgFileImpl::ConvertBufferToString(updateInfo_.curPartition, {data + offset, tlv.length});
506 LOG(DEBUG) << "PreWriteBin name " << updateInfo_.curPartition;
507
508 return true;
509 }
510
OpenDevPath()511 bool BinChunkUpdate::OpenDevPath()
512 {
513 #ifndef UPDATER_UT
514 std::string devPath = GetBlockDeviceByMountPoint(updateInfo_.curPartition);
515 std::string srcPath;
516 std::string targetPath;
517 srcPath = devPath;
518 targetPath = devPath;
519
520 if (updateInfo_.curPartition != "/userdata") {
521 std::string suffix = "";
522 GetPartitionSuffix(suffix);
523 targetPath += suffix;
524 GetActivePartitionSuffix(suffix);
525 srcPath += suffix;
526 }
527
528 LOG(DEBUG) << "ChunkInstallPreWrite curPartition:" << updateInfo_.curPartition
529 << " srcPath:" << srcPath << " targetPath:" << targetPath;
530
531 updateInfo_.srcFd = open(srcPath.c_str(), O_RDWR | O_LARGEFILE);
532 if (updateInfo_.srcFd < 0) {
533 LOG(ERROR) << "open srcPath error";
534 return false;
535 }
536
537 updateInfo_.targetFd = open(targetPath.c_str(), O_RDWR | O_LARGEFILE);
538 if (updateInfo_.targetFd < 0) {
539 LOG(ERROR) << "open targetPath error";
540 return false;
541 }
542 #else
543 int fd = open("/data/updater/test.txt", O_RDWR | O_LARGEFILE | O_CREAT);
544 if (fd < 0) {
545 LOG(ERROR) << "open test file error";
546 return false;
547 }
548 updateInfo_.srcFd = fd;
549 updateInfo_.targetFd = fd;
550 #endif
551 return true;
552 }
553
InitTransferParams()554 bool BinChunkUpdate::InitTransferParams()
555 {
556 updateInfo_.transferParams = std::make_unique<TransferParams>();
557 updateInfo_.transferParams->storeBase = std::string("/data/updater/") + updateInfo_.curPartition + "_tmp";
558 updateInfo_.transferParams->canWrite = true;
559
560 int32_t ret = Store::CreateNewSpace(updateInfo_.transferParams->storeBase, true);
561 if (ret == -1) {
562 LOG(ERROR) << "Error to create new store space";
563 return false;
564 }
565
566 return true;
567 }
568
ChunkInstallDoWrite(uint8_t * data,uint32_t & len)569 UpdateResultCode BinChunkUpdate::ChunkInstallDoWrite(uint8_t *data, uint32_t &len)
570 {
571 LOG(DEBUG) << "BinChunkUpdate::ChunkInstallDoWrite enter";
572 uint32_t offset = offset_;
573
574 // 处理安装分区
575 if (!ProcessPartition(data, len, offset)) {
576 return STREAM_UPDATE_SUCCESS;
577 }
578
579 // 处理安装命令
580 if (!ProcessCmdLine(data, len, offset)) {
581 return STREAM_UPDATE_SUCCESS;
582 }
583
584 // 处理安装数据
585 if (!ProcessInstallData(data, len, offset)) {
586 return STREAM_UPDATE_SUCCESS;
587 }
588
589 // 安装数据
590 if (!ExecuteCmdLine()) {
591 return STREAM_UPDATE_FAILURE;
592 }
593
594 offset_ = offset;
595 return STREAM_UPDATE_SUCCESS;
596 }
597
ProcessPartition(uint8_t * data,uint32_t & len,uint32_t & offset)598 bool BinChunkUpdate::ProcessPartition(uint8_t *data, uint32_t &len, uint32_t &offset)
599 {
600 PkgTlvHH tlv;
601 if ((len - offset) < sizeof(PkgTlvHH)) {
602 LOG(DEBUG) << "needNewData";
603 updateInfo_.needNewData = true;
604 return false;
605 }
606
607 tlv.type = ReadLE16(data + offset);
608 LOG(DEBUG) << "tlv.type:" << tlv.type;
609 if (tlv.type == BIN_UPDATE_HASH_TIP) {
610 updateInfo_.updateStep = CHUNK_INSTALL_STEP_POST;
611 return false;
612 }
613
614 tlv.length = ReadLE16(data + offset + sizeof(uint16_t));
615 LOG(DEBUG) << "tlv.length:" << tlv.length;
616 offset += sizeof(PkgTlvHH);
617
618 if ((len - offset) < tlv.length) {
619 LOG(DEBUG) << "needNewData";
620 updateInfo_.needNewData = true;
621 return false;
622 }
623
624 std::string partition;
625 PkgFileImpl::ConvertBufferToString(partition, {data + offset, tlv.length});
626 LOG(DEBUG) << "partition:" << partition;
627 offset += tlv.length;
628
629 if (partition != updateInfo_.curPartition) {
630 updateInfo_.updateStep = CHUNK_INSTALL_STEP_POST;
631 return false;
632 }
633
634 return true;
635 }
636
ProcessCmdLine(uint8_t * data,uint32_t & len,uint32_t & offset)637 bool BinChunkUpdate::ProcessCmdLine(uint8_t *data, uint32_t &len, uint32_t &offset)
638 {
639 PkgTlvHH tlv;
640 if ((len - offset) < sizeof(PkgTlvHH)) {
641 LOG(DEBUG) << "needNewData";
642 updateInfo_.needNewData = true;
643 return false;
644 }
645
646 tlv.type = ReadLE16(data + offset);
647 LOG(DEBUG) << "tlv.type:" << tlv.type;
648 tlv.length = ReadLE16(data + offset + sizeof(uint16_t));
649 LOG(DEBUG) << "tlv.length:" << tlv.length;
650 offset += sizeof(PkgTlvHH);
651
652 if ((len - offset) < tlv.length) {
653 LOG(DEBUG) << "needNewData";
654 updateInfo_.needNewData = true;
655 return false;
656 }
657
658 updateInfo_.cmdLine = "";
659 PkgFileImpl::ConvertBufferToString(updateInfo_.cmdLine, {data + offset, tlv.length});
660 LOG(DEBUG) << "cmdLine:" << updateInfo_.cmdLine;
661 offset += tlv.length;
662
663 return true;
664 }
665
ProcessInstallData(uint8_t * data,uint32_t & len,uint32_t & offset)666 bool BinChunkUpdate::ProcessInstallData(uint8_t *data, uint32_t &len, uint32_t &offset)
667 {
668 PkgTlvHI tlv2;
669 if ((len - offset) < sizeof(PkgTlvHI)) {
670 LOG(DEBUG) << "needNewData";
671 updateInfo_.needNewData = true;
672 return false;
673 }
674
675 tlv2.type = ReadLE16(data + offset);
676 LOG(DEBUG) << "tlv2.type:" << tlv2.type;
677 tlv2.length = ReadLE32(data + offset + sizeof(uint16_t));
678 LOG(DEBUG) << "tlv2.length:" << tlv2.length;
679 offset += sizeof(PkgTlvHI);
680
681 if ((len - offset) < tlv2.length) {
682 LOG(DEBUG) << "needNewData";
683 updateInfo_.needNewData = true;
684 return false;
685 }
686
687 updateInfo_.transferParams->dataBuffer = data + offset;
688 updateInfo_.transferParams->dataBufferSize = tlv2.length;
689
690 offset += tlv2.length;
691 return true;
692 }
693
ExecuteCmdLine()694 bool BinChunkUpdate::ExecuteCmdLine()
695 {
696 std::shared_ptr<Command> cmd = std::make_shared<Command>(updateInfo_.transferParams.get());
697 cmd->SetIsStreamCmd(true);
698 cmd->SetSrcFileDescriptor(updateInfo_.srcFd);
699 cmd->SetTargetFileDescriptor(updateInfo_.targetFd);
700 cmd->Init(updateInfo_.cmdLine);
701
702 CommandFunction *cf = CommandFunctionFactory::GetInstance().GetCommandFunction(cmd->GetCommandHead());
703 CommandResult ret = cf->Execute(const_cast<Command &>(*cmd.get()));
704 if (SUCCESS != ret) {
705 LOG(ERROR) << "cf->Execute fail";
706 return false;
707 }
708
709 LOG(INFO) << "cf->Execute SUCCESS";
710 return true;
711 }
712
ChunkInstallPostWrite(uint8_t * data,uint32_t & len)713 UpdateResultCode BinChunkUpdate::ChunkInstallPostWrite(uint8_t *data, uint32_t &len)
714 {
715 LOG(DEBUG) << "BinChunkUpdate::ChunkInstallPostWrite enter";
716 if (updateInfo_.srcFd > 0) {
717 fsync(updateInfo_.srcFd);
718 close(updateInfo_.srcFd);
719 }
720 if (updateInfo_.targetFd > 0) {
721 fsync(updateInfo_.targetFd);
722 close(updateInfo_.targetFd);
723 }
724 Store::DoFreeSpace(updateInfo_.transferParams->storeBase);
725 (void)Utils::DeleteFile(updateInfo_.transferParams->storeBase);
726 updateInfo_.updateStep = CHUNK_INSTALL_STEP_PRE;
727 return STREAM_UPDATE_SUCCESS;
728 }
729
UpdateBinData(uint8_t * data,uint32_t & len)730 UpdateResultCode BinChunkUpdate::UpdateBinData(uint8_t *data, uint32_t &len)
731 {
732 LOG(DEBUG) << "BinChunkUpdate::UpdateBinData enter";
733 UpdateResultCode ret;
734 do {
735 auto it = chunkInstallProcess_.find(updateInfo_.updateStep);
736 if (it == chunkInstallProcess_.end() || it->second == nullptr) {
737 LOG(ERROR) << "cannot find " << updateInfo_.updateStep;
738 return STREAM_UPDATE_FAILURE;
739 }
740 ret = it->second(data, len);
741 } while (!(updateInfo_.needNewData || ret == STREAM_UPDATE_FAILURE ||
742 updateInfo_.updateStep == CHUNK_INSTALL_STEP_PRE));
743
744 LOG(DEBUG) << "BinChunkUpdate::UpdateBinData exit";
745 return ret;
746 }
747
748 // 计算文件哈希值的函数
ComputeFileHash(const std::string & partitionName,const std::map<std::string,uint64_t> & dataLenInfos)749 std::string BinChunkUpdate::ComputeFileHash(const std::string &partitionName,
750 const std::map<std::string, uint64_t> &dataLenInfos)
751 {
752 LOG(DEBUG) << "BinChunkUpdate::ComputeFileHash enter";
753 std::vector<uint8_t> hash(SHA256_DIGEST_LENGTH);
754
755 auto it = dataLenInfos.find(partitionName);
756 if (it == dataLenInfos.end()) {
757 LOG(ERROR) << "ComputeFileHash cannot find dataLenInfos " << partitionName;
758 return "";
759 }
760 uint64_t dataLen = it->second;
761 #ifndef UPDATER_UT
762 std::string devPath = GetBlockDeviceByMountPoint(partitionName);
763 if (partitionName != "/userdata") {
764 std::string suffix = "";
765 GetPartitionSuffix(suffix);
766 devPath += suffix;
767 }
768 #else
769 std::string devPath = "/data/updater/test.txt";
770 #endif
771 std::ifstream file(devPath, std::ios::binary);
772 if (!file) {
773 LOG(ERROR) << "Failed to open file: " << partitionName;
774 return "";
775 }
776
777 SHA256_CTX sha256;
778 SHA256_Init(&sha256);
779
780 while (dataLen > 0) {
781 std::vector<char> buffer(HASH_BUFFER_SIZE);
782 size_t size = std::min(static_cast<size_t>(dataLen), buffer.size());
783 file.read(buffer.data(), size);
784 SHA256_Update(&sha256, buffer.data(), file.gcount());
785 dataLen -= file.gcount();
786 }
787
788 SHA256_Final(hash.data(), &sha256);
789 std::ostringstream oss;
790 oss << std::hex << std::setfill('0');
791 const int kByteWidth = 2;
792 for (auto byte : hash) {
793 oss << std::setw(kByteWidth) << static_cast<int>(byte);
794 }
795
796 return oss.str();
797 }
798
799 // 比对哈希值的函数
VerifyPartitionHash(const std::string & partitionName,const std::string & expectedHash,const std::map<std::string,uint64_t> & dataLenInfos)800 bool BinChunkUpdate::VerifyPartitionHash(const std::string &partitionName, const std::string &expectedHash,
801 const std::map<std::string, uint64_t> &dataLenInfos)
802 {
803 LOG(DEBUG) << "BinChunkUpdate::VerifyPartitionHash enter";
804 std::string actualHash = ComputeFileHash(partitionName, dataLenInfos);
805
806 LOG(DEBUG) << "actualHash:" << actualHash << " expectedHash:" << expectedHash;
807
808 if (actualHash != expectedHash) {
809 LOG(ERROR) << "Error verifying hash for partition " << partitionName;
810 return false;
811 }
812 return true;
813 }
814
815 } // namespace Updater
816