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