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
16 #include "bin_process.h"
17 #include <string>
18 #include <thread>
19 #include "applypatch/partition_record.h"
20 #include "log.h"
21 #include "pkg_manager_impl.h"
22 #include "pkg_package/pkg_pkgfile.h"
23 #include "pkg_utils.h"
24 #include "ring_buffer/ring_buffer.h"
25 #include "script_manager.h"
26 #include "threadpool/thread_pool.h"
27 #include "scope_guard.h"
28 #include "securec.h"
29 #include "updater/updater_const.h"
30
31 using namespace std;
32 using namespace Hpackage;
33 using namespace Uscript;
34
35 namespace Updater {
36 constexpr uint32_t STASH_BUFFER_SIZE = 4 * 1024 * 1024;
37 constexpr uint32_t MAX_BUFFER_NUM = 16;
38 constexpr uint8_t ES_IMAGE = 6;
39 constexpr uint8_t CS_IMAGE = 7;
40 constexpr uint8_t NEED_VERIFY_CS_IMAGE = 8;
41
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)42 int32_t UScriptInstructionBinFlowWrite::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
43 {
44 std::string upgradeFileName;
45 int32_t ret = context.GetParam(0, upgradeFileName);
46 if (ret != USCRIPT_SUCCESS) {
47 LOG(ERROR) << "Error to get bin file";
48 return ret;
49 }
50
51 LOG(INFO) << "UScriptInstructionUpdateFromZip::Execute " << upgradeFileName;
52 PkgManager::PkgManagerPtr pkgManager = env.GetPkgManager();
53 if (pkgManager == nullptr) {
54 LOG(ERROR) << "Error to get pkg manager";
55 return USCRIPT_INVALID_PARAM;
56 }
57
58 RingBuffer ringBuffer;
59 if (!ringBuffer.Init(STASH_BUFFER_SIZE, MAX_BUFFER_NUM)) {
60 LOG(ERROR) << "Error to get ringbuffer";
61 return USCRIPT_INVALID_PARAM;
62 }
63
64 fullUpdateProportion_ = GetScriptProportion();
65 stashBuffer_.data.resize(STASH_BUFFER_SIZE);
66 stashBuffer_.buffer = stashBuffer_.data.data();
67 PkgManager::StreamPtr binFlowStream = nullptr;
68 const FileInfo *info = pkgManager->GetFileInfo(upgradeFileName);
69 if (info == nullptr) {
70 LOG(ERROR) << "Get file info fail " << upgradeFileName;
71 return PKG_INVALID_FILE;
72 }
73 ret = pkgManager->CreatePkgStream(binFlowStream, upgradeFileName, info->unpackedSize, &ringBuffer);
74 if (ret != USCRIPT_SUCCESS || binFlowStream == nullptr) {
75 LOG(ERROR) << "Error to create output stream";
76 return USCRIPT_INVALID_PARAM;
77 }
78
79 std::thread consumer([this, &env, &context, binFlowStream] {
80 this->ProcessBinFile(env, context, binFlowStream);
81 });
82 std::thread producer([this, &env, &context, binFlowStream] {
83 this->ExtractBinFile(env, context, binFlowStream);
84 });
85 consumer.join();
86 producer.join();
87 if (isStopRun_) {
88 LOG(ERROR) << "Error to Execute bin file update";
89 env.PostMessage(UPDATER_RETRY_TAG, PROCESS_BIN_FAIL_RETRY);
90 return USCRIPT_ERROR_EXECUTE;
91 }
92 return USCRIPT_SUCCESS;
93 }
94
ExtractBinFile(Uscript::UScriptEnv & env,Uscript::UScriptContext & context,PkgManager::StreamPtr stream)95 int32_t UScriptInstructionBinFlowWrite::ExtractBinFile(Uscript::UScriptEnv &env, Uscript::UScriptContext &context,
96 PkgManager::StreamPtr stream)
97 {
98 ON_SCOPE_EXIT(failExecute) {
99 isStopRun_ = true;
100 stream->Stop();
101 };
102 std::string upgradeFileName;
103 int32_t ret = context.GetParam(0, upgradeFileName);
104 if (ret != USCRIPT_SUCCESS) {
105 LOG(ERROR) << "Error to get bin file";
106 return ret;
107 }
108
109 LOG(INFO) << "UScriptInstructionBinFlowWrite::ExtractBinFile " << upgradeFileName;
110 PkgManager::PkgManagerPtr pkgManager = env.GetPkgManager();
111 if (pkgManager == nullptr) {
112 LOG(ERROR) << "Error to get pkg manager";
113 return USCRIPT_INVALID_PARAM;
114 }
115
116 PkgManager::StreamPtr processStream = nullptr;
117 PkgStream::ExtractFileProcessor processor =
118 [this](const PkgBuffer &buffer, size_t size, size_t start, bool isFinish, const void *context) {
119 return this->UnCompressDataProducer(buffer, size, start, isFinish, context);
120 };
121 ret = pkgManager->CreatePkgStream(processStream, upgradeFileName, processor, stream);
122 if (ret != USCRIPT_SUCCESS || processStream == nullptr) {
123 LOG(ERROR) << "Error to create output stream";
124 return USCRIPT_INVALID_PARAM;
125 }
126
127 ret = pkgManager->ExtractFile(upgradeFileName, processStream);
128 if (ret != USCRIPT_SUCCESS) {
129 LOG(ERROR) << "Error to extract" << upgradeFileName;
130 pkgManager->ClosePkgStream(processStream);
131 return USCRIPT_ERROR_EXECUTE;
132 }
133 pkgManager->ClosePkgStream(processStream);
134 CANCEL_SCOPE_EXIT_GUARD(failExecute);
135 return USCRIPT_SUCCESS;
136 }
137
UnCompressDataProducer(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)138 int32_t UScriptInstructionBinFlowWrite::UnCompressDataProducer(const PkgBuffer &buffer, size_t size, size_t start,
139 bool isFinish, const void *context)
140 {
141 if (isStopRun_) {
142 LOG(ERROR) << "recive stop single, UnCompressDataProducer stop run";
143 return USCRIPT_ERROR_EXECUTE;
144 }
145
146 void *p = const_cast<void *>(context);
147 PkgStream *flowStream = static_cast<PkgStream *>(p);
148 if (flowStream == nullptr) {
149 LOG(ERROR) << "ring buffer is nullptr";
150 return PKG_INVALID_STREAM;
151 }
152
153 if (buffer.buffer == nullptr && size == 0 && isFinish) {
154 // 最后一块数据
155 if (stashDataSize_ != 0) {
156 size_t writeOffset = flowStream->GetFileLength() - stashDataSize_;
157 if (flowStream->Write(stashBuffer_, stashDataSize_, writeOffset) != USCRIPT_SUCCESS) {
158 LOG(ERROR) << "UnCompress flowStream write fail";
159 return USCRIPT_ERROR_EXECUTE;
160 }
161 stashDataSize_ = 0;
162 }
163 LOG(INFO) << "extract finished, start";
164 return USCRIPT_SUCCESS;
165 }
166
167 if (buffer.buffer == nullptr || size == 0 || start < stashDataSize_) {
168 LOG(ERROR) << "invalid para, size: " << size << "start: " << start;
169 return USCRIPT_ERROR_EXECUTE;
170 }
171
172 size_t writeSize = 0;
173 size_t copyLen = 0;
174 // 缓存4M再写入数据流
175 while (size - writeSize > STASH_BUFFER_SIZE - stashDataSize_) {
176 copyLen = STASH_BUFFER_SIZE - stashDataSize_;
177 if (memcpy_s(stashBuffer_.buffer + stashDataSize_, copyLen, buffer.buffer + writeSize, copyLen) != EOK) {
178 return USCRIPT_ERROR_EXECUTE;
179 }
180
181 if (flowStream->Write(stashBuffer_, STASH_BUFFER_SIZE, start - stashDataSize_) != USCRIPT_SUCCESS) {
182 LOG(ERROR) << "UnCompress flowStream write fail";
183 return USCRIPT_ERROR_EXECUTE;
184 }
185 writeSize += copyLen;
186 stashDataSize_ = 0;
187 }
188
189 copyLen = size - writeSize;
190 if (memcpy_s(stashBuffer_.buffer + stashDataSize_, copyLen, buffer.buffer + writeSize, copyLen) != EOK) {
191 return USCRIPT_ERROR_EXECUTE;
192 }
193 stashDataSize_ += copyLen;
194 if (stashDataSize_ == STASH_BUFFER_SIZE) {
195 if (flowStream->Write(stashBuffer_, stashDataSize_, start - stashDataSize_ + copyLen) != USCRIPT_SUCCESS) {
196 LOG(ERROR) << "UnCompress flowStream write fail";
197 return USCRIPT_ERROR_EXECUTE;
198 }
199 stashDataSize_ = 0;
200 }
201 return PKG_SUCCESS;
202 }
203
ProcessBinFile(Uscript::UScriptEnv & env,Uscript::UScriptContext & context,PkgManager::StreamPtr stream)204 int32_t UScriptInstructionBinFlowWrite::ProcessBinFile(Uscript::UScriptEnv &env, Uscript::UScriptContext &context,
205 PkgManager::StreamPtr stream)
206 {
207 if (stream == nullptr) {
208 LOG(ERROR) << "Error to get file stream";
209 return USCRIPT_ERROR_EXECUTE;
210 }
211 ON_SCOPE_EXIT(failExecute) {
212 isStopRun_ = true;
213 stream->Stop();
214 };
215 std::string pkgFileName;
216 int32_t ret = context.GetParam(0, pkgFileName);
217 if (ret != USCRIPT_SUCCESS) {
218 LOG(ERROR) << "Error to get pkgFileName";
219 return ret;
220 }
221
222 LOG(INFO) << "UScriptInstructionBinFlowWrite::Execute " << pkgFileName;
223 PkgManager::PkgManagerPtr manager = env.GetPkgManager();
224 if (manager == nullptr) {
225 LOG(ERROR) << "Error to get pkg manager";
226 return USCRIPT_INVALID_PARAM;
227 }
228 std::vector<std::string> innerFileNames;
229 ret = manager->LoadPackageWithStream(pkgFileName, Utils::GetCertName(),
230 innerFileNames, PkgFile::PKG_TYPE_UPGRADE, stream);
231 if (ret != USCRIPT_SUCCESS) {
232 LOG(ERROR) << "Error to load flow data stream";
233 return USCRIPT_ERROR_EXECUTE;
234 }
235
236 for (const auto &iter : innerFileNames) {
237 // 根据镜像名称获取分区名称和大小
238 std::string partitionName = iter;
239 const FileInfo *info = manager->GetFileInfo(partitionName);
240 if (info == nullptr) {
241 LOG(ERROR) << "Error to get file info";
242 return USCRIPT_ERROR_EXECUTE;
243 }
244
245 LOG(INFO) << " start process Component " << partitionName << " unpackedSize " << info->unpackedSize;
246 if (ComponentProcess(env, stream, partitionName, *info) != USCRIPT_SUCCESS) {
247 LOG(ERROR) << "Error to process " << partitionName;
248 return USCRIPT_ERROR_EXECUTE;
249 }
250 }
251 CANCEL_SCOPE_EXIT_GUARD(failExecute);
252 LOG(INFO)<<"UScriptInstructionBinFlowWrite finish";
253 return USCRIPT_SUCCESS;
254 }
255
IsMatchedCsEsIamge(const Hpackage::FileInfo & fileInfo)256 bool UScriptInstructionBinFlowWrite::IsMatchedCsEsIamge(const Hpackage::FileInfo &fileInfo)
257 {
258 if ((fileInfo.resType == ES_IMAGE && !Utils::IsEsDevice()) ||
259 (fileInfo.resType == CS_IMAGE && Utils::IsEsDevice())) {
260 LOG(INFO) << "not matched cs es image, skip write";
261 return false;
262 }
263 return true;
264 }
265
CheckEsDeviceUpdate(const Hpackage::FileInfo & fileInfo)266 bool UScriptInstructionBinFlowWrite::CheckEsDeviceUpdate(const Hpackage::FileInfo &fileInfo)
267 {
268 if (fileInfo.resType == NEED_VERIFY_CS_IMAGE && Utils::IsEsDevice()) {
269 LOG(ERROR) << "pkg just cs image, but device is es";
270 return false;
271 }
272 return true;
273 }
274
SetProportion(float proportion)275 void UScriptInstructionBinFlowWrite::SetProportion(float proportion)
276 {
277 fullUpdateProportion_ = proportion;
278 }
279
ComponentProcess(Uscript::UScriptEnv & env,PkgManager::StreamPtr stream,const std::string & name,const Hpackage::FileInfo & fileInfo)280 int32_t UScriptInstructionBinFlowWrite::ComponentProcess(Uscript::UScriptEnv &env, PkgManager::StreamPtr stream,
281 const std::string &name, const Hpackage::FileInfo &fileInfo)
282 {
283 size_t fileSize = fileInfo.unpackedSize;
284 // 根据镜像名获取组件处理类名
285 std::unique_ptr<ComponentProcessor> processor =
286 ComponentProcessorFactory::GetInstance().GetProcessor(name, fileSize);
287
288 if (env.IsRetry()) {
289 LOG(DEBUG) << "Retry updater, check if current partition updated already during last time";
290 bool isUpdated = PartitionRecord::GetInstance().IsPartitionUpdated(name);
291 if (isUpdated) {
292 LOG(INFO) << name << " already updated, skip";
293 processor.reset();
294 processor = std::make_unique<SkipImgProcessor>(name, fileSize);
295 }
296 }
297
298 if (!CheckEsDeviceUpdate(fileInfo)) {
299 LOG(ERROR) << "pkg just cs image, es device not allow update";
300 return USCRIPT_ERROR_EXECUTE;
301 }
302
303 if ((processor == nullptr && fileInfo.resType == UPGRADE_FILE_COMP_OTHER_TPYE) ||
304 !IsMatchedCsEsIamge(fileInfo)) {
305 LOG(INFO) << name << " comp is not register and comp file is not image, or not match cs es image, skip";
306 processor.reset();
307 processor = std::make_unique<SkipImgProcessor>(name, fileSize);
308 }
309
310 if (processor == nullptr) {
311 LOG(ERROR) << "GetProcessor failed, partition name: " << name;
312 return USCRIPT_ERROR_EXECUTE;
313 }
314 processor->SetPkgFileInfo(stream->GetReadOffset(), stream->GetFileLength(),
315 fullUpdateProportion_ * GetTotalProportion());
316 LOG(INFO) << "component read offset " << stream->GetReadOffset();
317
318 if (processor->PreProcess(env) != USCRIPT_SUCCESS) {
319 LOG(ERROR) << "Error to PreProcess " << name;
320 return USCRIPT_ERROR_EXECUTE;
321 }
322
323 if (processor->DoProcess(env) != USCRIPT_SUCCESS) {
324 LOG(ERROR) << "Error to DoProcess " << name;
325 return USCRIPT_ERROR_EXECUTE;
326 }
327
328 if (processor->PostProcess(env) != USCRIPT_SUCCESS) {
329 LOG(ERROR) << "Error to PostProcess " << name;
330 return USCRIPT_ERROR_EXECUTE;
331 }
332
333 return USCRIPT_SUCCESS;
334 }
335 } // namespace Updater
336