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