1 /*
2 * Copyright (c) 2023 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_flow_update.h"
16
17 #include <algorithm>
18 #include <functional>
19
20 #include "log.h"
21 #include "scope_guard.h"
22 #include "pkg_manager/pkg_stream.h"
23 #include "pkg_package/pkg_pkgfile.h"
24 #include "securec.h"
25 #include "utils.h"
26
27 namespace Updater {
28 using namespace Uscript;
29 using namespace Hpackage;
30 using namespace std::placeholders;
31
32 constexpr const char *UPDATE_BIN_FILE = "update.bin";
33 constexpr uint32_t DEFAULT_SIZE = 4 * 1024 * 1024;
34
BinFlowUpdate(uint32_t maxBufSize)35 BinFlowUpdate::BinFlowUpdate(uint32_t maxBufSize)
36 {
37 maxBufSize_ = maxBufSize == 0 ? DEFAULT_SIZE : maxBufSize;
38 buffer_ = new uint8_t[maxBufSize_];
39 updateBinProcess_.emplace(BIN_UPDATE_STEP_PRE, std::bind(&BinFlowUpdate::BinUpdatePreWrite, this, _1, _2));
40 updateBinProcess_.emplace(BIN_UPDATE_STEP_DO, std::bind(&BinFlowUpdate::BinUpdateDoWrite, this, _1, _2));
41 updateBinProcess_.emplace(BIN_UPDATE_STEP_POST, std::bind(&BinFlowUpdate::BinUpdatePostWrite, this, _1, _2));
42 pkgManager_ = PkgManager::CreatePackageInstance();
43 }
44
~BinFlowUpdate()45 BinFlowUpdate::~BinFlowUpdate()
46 {
47 PkgManager::ReleasePackageInstance(pkgManager_);
48 if (buffer_ != nullptr) {
49 delete[] buffer_;
50 buffer_ = nullptr;
51 }
52 }
53
StartBinFlowUpdate(uint8_t * data,uint32_t len)54 int32_t BinFlowUpdate::StartBinFlowUpdate(uint8_t *data, uint32_t len)
55 {
56 if (data == nullptr || len == 0 || pkgManager_ == nullptr) {
57 LOG(ERROR) << "para error";
58 return -1;
59 }
60 uint32_t remainLen = len;
61 while (remainLen > 0) {
62 // 1: add remained data
63 if (!AddRemainData(data + len - remainLen, remainLen)) {
64 LOG(ERROR) << "AddRemainData error";
65 return -1;
66 }
67
68 // 2: parse head
69 if (!headInit_ && UpdateBinHead(buffer_, curlen_) != 0) {
70 LOG(ERROR) << "ParseHead error";
71 return -1;
72 }
73
74 // 3: process data
75 updateInfo_.needNewData = false;
76 while (curlen_ > 0 && !updateInfo_.needNewData) {
77 if (auto ret = UpdateBinData(buffer_, curlen_); ret != 0) {
78 LOG(ERROR) << "ProcessData error";
79 return ret;
80 }
81 }
82 }
83 return 0;
84 }
85
AddRemainData(uint8_t * data,uint32_t & len)86 bool BinFlowUpdate::AddRemainData(uint8_t *data, uint32_t &len)
87 {
88 uint32_t copySize = std::min(static_cast<size_t>(len), static_cast<size_t>(maxBufSize_ - curlen_));
89 if (memcpy_s(buffer_ + curlen_, maxBufSize_, data, copySize) != EOK) {
90 LOG(ERROR) << "AddRemainData memcpy failed" << " : " << strerror(errno);
91 return false;
92 }
93 curlen_ += copySize;
94 len -= copySize;
95 return true;
96 }
97
98
UpdateBinHead(uint8_t * data,uint32_t & len)99 uint32_t BinFlowUpdate::UpdateBinHead(uint8_t *data, uint32_t &len)
100 {
101 PkgManager::StreamPtr stream = nullptr;
102 PkgBuffer buffer(data, len);
103 if (auto ret = pkgManager_->CreatePkgStream(stream, UPDATE_BIN_FILE, buffer); ret != PKG_SUCCESS) {
104 LOG(ERROR) << "ParseHead failed";
105 return -1;
106 }
107
108 if (auto ret = pkgManager_->LoadPackageWithStream(UPDATE_BIN_FILE, Utils::GetCertName(),
109 updateInfo_.componentNames, PkgFile::PKG_TYPE_UPGRADE, stream); ret != PKG_SUCCESS) {
110 LOG(ERROR) << "LoadPackage fail ret :"<< ret;
111 return ret;
112 }
113
114 const PkgInfo *pkgInfo = pkgManager_->GetPackageInfo(UPDATE_BIN_FILE);
115 if (pkgInfo == nullptr || pkgInfo->updateFileHeadLen == 0 || len < pkgInfo->updateFileHeadLen) {
116 LOG(ERROR) << "GetPackageInfo failed";
117 return -1;
118 }
119
120 if (len > pkgInfo->updateFileHeadLen &&
121 memmove_s(data, len, data + pkgInfo->updateFileHeadLen, len - pkgInfo->updateFileHeadLen) != EOK) {
122 LOG(ERROR) << "memmove failed";
123 return -1;
124 }
125
126 len -= pkgInfo->updateFileHeadLen;
127 headInit_ = true;
128 return 0;
129 }
130
GetDataWriter(const std::string & partition)131 std::unique_ptr<DataWriter> BinFlowUpdate::GetDataWriter(const std::string &partition)
132 {
133 static std::string lastPartition {};
134 static int lastIndex = 0;
135 if (lastPartition == partition) {
136 lastIndex++;
137 lastPartition = partition + std::to_string(lastIndex);
138 } else {
139 lastPartition = partition;
140 lastIndex = 0;
141 }
142 const std::string writePath = "/data/updater" + lastPartition;
143 FILE *pFile = fopen(writePath.c_str(), "w+");
144 if (pFile != nullptr) {
145 uint8_t data[1] {};
146 fwrite(data, 1, sizeof(data), pFile);
147 fclose(pFile);
148 }
149 LOG(INFO) << "GetDataWriter writePath " << writePath.c_str();
150 return DataWriter::CreateDataWriter(WRITE_RAW, writePath, static_cast<uint64_t>(0));
151 }
152
BinUpdatePreWrite(uint8_t * data,uint32_t & len)153 int BinFlowUpdate::BinUpdatePreWrite(uint8_t *data, uint32_t &len)
154 {
155 if (procCompIndex_ >= updateInfo_.componentNames.size()) {
156 LOG(ERROR) << "PreWriteBin index error cur:" << procCompIndex_ << " max:" << updateInfo_.componentNames.size();
157 return -1;
158 }
159
160 LOG(INFO) << "PreWriteBin name "<< updateInfo_.componentNames[procCompIndex_];
161 updateInfo_.imageWriteLen = 0;
162 updateInfo_.writer = GetDataWriter(updateInfo_.componentNames[procCompIndex_]);
163 if (updateInfo_.writer == nullptr) {
164 LOG(ERROR) << "GetDataWriter error";
165 return -1;
166 }
167
168 updateInfo_.info = pkgManager_->GetFileInfo(updateInfo_.componentNames[procCompIndex_]);
169 if (updateInfo_.info == nullptr) {
170 LOG(ERROR) << ("Can not get file info");
171 return -1;
172 }
173
174 updateInfo_.updateStep = BIN_UPDATE_STEP_DO;
175 return 0;
176 }
177
BinUpdateDoWrite(uint8_t * data,uint32_t & len)178 int BinFlowUpdate::BinUpdateDoWrite(uint8_t *data, uint32_t &len)
179 {
180 size_t writeLen = std::min(static_cast<size_t>(updateInfo_.info->unpackedSize - updateInfo_.imageWriteLen),
181 static_cast<size_t>(len));
182 LOG(INFO) << "DoWriteBin len " << len << " unpackedSize " << updateInfo_.info->unpackedSize << " already write " <<
183 updateInfo_.imageWriteLen;
184
185 if (!updateInfo_.writer->Write(data, writeLen, nullptr)) {
186 LOG(ERROR) << "Write failed";
187 return -1;
188 }
189
190 if (memmove_s(data, len, data + writeLen, len - writeLen) != EOK) {
191 LOG(ERROR) << "memmove failed";
192 return -1;
193 }
194
195 updateInfo_.imageWriteLen += writeLen;
196 len -= writeLen;
197 if (updateInfo_.imageWriteLen == updateInfo_.info->unpackedSize) {
198 LOG(INFO) << "DoWriteBin all len " << updateInfo_.imageWriteLen;
199 updateInfo_.updateStep = BIN_UPDATE_STEP_POST;
200 } else if (updateInfo_.imageWriteLen > updateInfo_.info->unpackedSize) {
201 LOG(INFO) << "DoWriteBin write len " << updateInfo_.imageWriteLen <<
202 " all len " << updateInfo_.info->unpackedSize;
203 return -1;
204 }
205
206 return 0;
207 }
208
BinUpdatePostWrite(uint8_t * data,uint32_t & len)209 int BinFlowUpdate::BinUpdatePostWrite(uint8_t *data, uint32_t &len)
210 {
211 procCompIndex_++;
212 updateInfo_.updateStep = BIN_UPDATE_STEP_PRE;
213 return 0;
214 }
215
UpdateBinData(uint8_t * data,uint32_t & len)216 int BinFlowUpdate::UpdateBinData(uint8_t *data, uint32_t &len)
217 {
218 auto it = updateBinProcess_.find(updateInfo_.updateStep);
219 if (it == updateBinProcess_.end() || it->second == nullptr) {
220 LOG(ERROR) << "cannot find " << updateInfo_.updateStep;
221 return -1;
222 }
223
224 return it->second(data, len);
225 }
226 } // Updater
227